Skip to content

Commit 3be647b

Browse files
committed
feat: chapter 5
1 parent b43913c commit 3be647b

File tree

2 files changed

+168
-29
lines changed

2 files changed

+168
-29
lines changed

modules/5-elixir.livemd

+141-27
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ Mix.install([
55
{:grading_client, path: "#{__DIR__}/grading_client"},
66
{:benchwarmer, github: "mroth/benchwarmer", ref: "12b5a96b38cef09f2bd49e5c2dd5024100c1e8af"},
77
:uuid,
8-
:kino,
98
:plug
109
])
1110
```
@@ -51,18 +50,53 @@ Beware of functions in applications/libraries that create atoms from input value
5150

5251
_You should get a `true` result when you successfully fix the function._
5352

53+
<!-- livebook:{"attrs":"eyJzb3VyY2UiOiIjIEVMSVhJUl9TRUNVUklUWToxXG5tYWxpY2lvdXNfdXNlcl9pbnB1dCA9IFVVSUQudXVpZDQoKVxuXG50cnkgZG9cbiAgbWFsaWNpb3VzX3VzZXJfaW5wdXRcbiAgIyBPTkxZIENIQU5HRSBORVhUIExJTkVcbiAgfD4gU3RyaW5nLnRvX2F0b20oKVxucmVzY3VlXG4gIGUgLT4gZVxuZW5kIn0","chunks":null,"kind":"Elixir.GradingClient.GradedCell","livebook_object":"smart_cell"} -->
54+
5455
```elixir
55-
malicious_user_input = UUID.uuid4()
56+
result =
57+
(
58+
malicious_user_input = UUID.uuid4()
59+
60+
try do
61+
malicious_user_input |> String.to_atom()
62+
rescue
63+
e -> e
64+
end
65+
)
66+
67+
[module_id, question_id] =
68+
"# ELIXIR_SECURITY:1\nmalicious_user_input = UUID.uuid4()\n\ntry do\n malicious_user_input\n # ONLY CHANGE NEXT LINE\n |> String.to_atom()\nrescue\n e -> e\nend"
69+
|> String.split("\n", parts: 2)
70+
|> hd()
71+
|> String.trim_leading("#")
72+
|> String.split(":", parts: 2)
73+
74+
module_id =
75+
case %{
76+
"ELIXIR_SECURITY" => ELIXIR_SECURITY,
77+
"GRAPHQL" => GRAPHQL,
78+
"OWASP" => OWASP,
79+
"SDLC" => SDLC
80+
}[String.trim(module_id)] do
81+
nil -> raise "invalid module id: #{module_id}"
82+
module_id -> module_id
83+
end
5684

57-
try do
58-
malicious_user_input
59-
# ONLY CHANGE NEXT LINE
60-
|> String.to_atom()
61-
rescue
62-
_ ->
63-
IO.puts("Are you protected against Atom Exhaustion?")
64-
IO.puts("true")
65-
nil
85+
question_id =
86+
case Integer.parse(String.trim(question_id)) do
87+
{id, ""} -> id
88+
_ -> raise "invalid question id: #{question_id}"
89+
end
90+
91+
case GradingClient.check_answer(module_id, question_id, result) do
92+
:correct ->
93+
IO.puts([IO.ANSI.green(), "Correct!", IO.ANSI.reset()])
94+
95+
{:incorrect, help_text} when is_binary(help_text) ->
96+
IO.puts([IO.ANSI.red(), "Incorrect: ", IO.ANSI.reset(), help_text])
97+
98+
_ ->
99+
IO.puts([IO.ANSI.red(), "Incorrect.", IO.ANSI.reset()])
66100
end
67101
```
68102

@@ -203,25 +237,66 @@ The latter will raise a `BadBooleanError` when the function returns `:ok` or `{:
203237

204238
_Uncomment the if statement that uses the correct boolean comparison._
205239

240+
<!-- livebook:{"attrs":"eyJzb3VyY2UiOiIjIEVMSVhJUl9TRUNVUklUWToyXG5cbmRlZm1vZHVsZSBTZWN1cml0eUNoZWNrIGRvXG4gIGRlZiB2YWxpZGF0ZShpbnB1dCwgcGFzc3dvcmRfaGFzaCkgZG9cbiAgICBjYXNlIFBsdWcuQ3J5cHRvLnNlY3VyZV9jb21wYXJlKGlucHV0LCBwYXNzd29yZF9oYXNoKSBkb1xuICAgICAgdHJ1ZSAtPiA6b2tcbiAgICAgIGZhbHNlIC0+IDphY2Nlc3NfZGVuaWVkXG4gICAgZW5kXG4gIGVuZFxuXG4gIGRlZmV4Y2VwdGlvbiBtZXNzYWdlOiBcIlRoZXJlIHdhcyBhbiBpc3N1ZVwiXG5lbmRcblxucGFzc3dvcmQgPSBcInNvbWVfc2VjdXJlX3Bhc3N3b3JkX2hhc2hcIlxudXNlcl9pbnB1dCA9IFwic29tZV9zdHJpbmdfd2hpY2hfb2J2aW91c2x5X2lzbnRfdGhlX3NhbWVfYXNfdGhlX3Bhc3N3b3JkXCJcbjpva1xuIyBETyBOT1QgRURJVCBBTlkgQ09ERSBBQk9WRSBUSElTIExJTkUgPT09PT09PT09PT09PT09PT09PT09XG5cbnRyeSBkb1xuIyBpZiBTZWN1cml0eUNoZWNrLnZhbGlkYXRlKHVzZXJfaW5wdXQsIHBhc3N3b3JkKSBvciByYWlzZShTZWN1cml0eUNoZWNrKSBkbyA6eW91X2xldF9hX2JhZGRpZV9pbiBlbmRcbiMgaWYgU2VjdXJpdHlDaGVjay52YWxpZGF0ZSh1c2VyX2lucHV0LCBwYXNzd29yZCkgfHwgcmFpc2UoU2VjdXJpdHlDaGVjaykgZG8gOnlvdV9sZXRfYV9iYWRkaWVfaW4gZW5kXG5yZXNjdWVcbiAgZSAtPiBlXG5lbmQifQ","chunks":null,"kind":"Elixir.GradingClient.GradedCell","livebook_object":"smart_cell"} -->
241+
206242
```elixir
207-
defmodule SecurityCheck do
208-
def validate(input, password_hash) do
209-
case Plug.Crypto.secure_compare(input, password_hash) do
210-
true -> :ok
211-
false -> :access_denied
243+
result =
244+
(
245+
defmodule SecurityCheck do
246+
def validate(input, password_hash) do
247+
case Plug.Crypto.secure_compare(input, password_hash) do
248+
true -> :ok
249+
false -> :access_denied
250+
end
251+
end
252+
253+
defexception message: "There was an issue"
254+
end
255+
256+
password = "some_secure_password_hash"
257+
user_input = "some_string_which_obviously_isnt_the_same_as_the_password"
258+
:ok
259+
260+
try do
261+
rescue
262+
e -> e
212263
end
264+
)
265+
266+
[module_id, question_id] =
267+
"# ELIXIR_SECURITY:2\n\ndefmodule SecurityCheck do\n def validate(input, password_hash) do\n case Plug.Crypto.secure_compare(input, password_hash) do\n true -> :ok\n false -> :access_denied\n end\n end\n\n defexception message: \"There was an issue\"\nend\n\npassword = \"some_secure_password_hash\"\nuser_input = \"some_string_which_obviously_isnt_the_same_as_the_password\"\n:ok\n# DO NOT EDIT ANY CODE ABOVE THIS LINE =====================\n\ntry do\n# if SecurityCheck.validate(user_input, password) or raise(SecurityCheck) do :you_let_a_baddie_in end\n# if SecurityCheck.validate(user_input, password) || raise(SecurityCheck) do :you_let_a_baddie_in end\nrescue\n e -> e\nend"
268+
|> String.split("\n", parts: 2)
269+
|> hd()
270+
|> String.trim_leading("#")
271+
|> String.split(":", parts: 2)
272+
273+
module_id =
274+
case %{
275+
"ELIXIR_SECURITY" => ELIXIR_SECURITY,
276+
"GRAPHQL" => GRAPHQL,
277+
"OWASP" => OWASP,
278+
"SDLC" => SDLC
279+
}[String.trim(module_id)] do
280+
nil -> raise "invalid module id: #{module_id}"
281+
module_id -> module_id
213282
end
214283

215-
defexception message: "There was an issue"
216-
end
284+
question_id =
285+
case Integer.parse(String.trim(question_id)) do
286+
{id, ""} -> id
287+
_ -> raise "invalid question id: #{question_id}"
288+
end
217289

218-
password = "some_secure_password_hash"
219-
user_input = "some_string_which_obviously_isnt_the_same_as_the_password"
220-
:ok
221-
# DO NOT EDIT ANY CODE ABOVE THIS LINE =====================
290+
case GradingClient.check_answer(module_id, question_id, result) do
291+
:correct ->
292+
IO.puts([IO.ANSI.green(), "Correct!", IO.ANSI.reset()])
293+
294+
{:incorrect, help_text} when is_binary(help_text) ->
295+
IO.puts([IO.ANSI.red(), "Incorrect: ", IO.ANSI.reset(), help_text])
222296

223-
# if SecurityCheck.validate(user_input, password) or raise(SecurityCheck) do :you_let_a_baddie_in end
224-
# if SecurityCheck.validate(user_input, password) || raise(SecurityCheck) do :you_let_a_baddie_in end
297+
_ ->
298+
IO.puts([IO.ANSI.red(), "Incorrect.", IO.ANSI.reset()])
299+
end
225300
```
226301

227302
## Sensitive Data Exposure
@@ -277,10 +352,49 @@ This prevents the table from being read by other processes, such as remote shell
277352

278353
**We have decided that we do not want this ETS table to be read from other processes, so try making it private:**
279354

355+
<!-- livebook:{"attrs":"eyJzb3VyY2UiOiIjIEVMSVhJUl9TRUNVUklUWTozXG5cbiMgT05MWSBFRElUIFRISVMgTElORVxuc2VjcmV0X3RhYmxlID0gOmV0cy5uZXcoOnNlY3JldF90YWJsZSwgWzpwdWJsaWNdKVxuOmV0cy5pbmZvKHNlY3JldF90YWJsZSlbOnByb3RlY3Rpb25dIn0","chunks":null,"kind":"Elixir.GradingClient.GradedCell","livebook_object":"smart_cell"} -->
356+
280357
```elixir
281-
# ONLY EDIT THIS LINE
282-
secret_table = :ets.new(:secret_table, [:public])
283-
:ets.info(secret_table)[:protection]
358+
result =
359+
(
360+
secret_table = :ets.new(:secret_table, [:public])
361+
:ets.info(secret_table)[:protection]
362+
)
363+
364+
[module_id, question_id] =
365+
"# ELIXIR_SECURITY:3\n\n# ONLY EDIT THIS LINE\nsecret_table = :ets.new(:secret_table, [:public])\n:ets.info(secret_table)[:protection]"
366+
|> String.split("\n", parts: 2)
367+
|> hd()
368+
|> String.trim_leading("#")
369+
|> String.split(":", parts: 2)
370+
371+
module_id =
372+
case %{
373+
"ELIXIR_SECURITY" => ELIXIR_SECURITY,
374+
"GRAPHQL" => GRAPHQL,
375+
"OWASP" => OWASP,
376+
"SDLC" => SDLC
377+
}[String.trim(module_id)] do
378+
nil -> raise "invalid module id: #{module_id}"
379+
module_id -> module_id
380+
end
381+
382+
question_id =
383+
case Integer.parse(String.trim(question_id)) do
384+
{id, ""} -> id
385+
_ -> raise "invalid question id: #{question_id}"
386+
end
387+
388+
case GradingClient.check_answer(module_id, question_id, result) do
389+
:correct ->
390+
IO.puts([IO.ANSI.green(), "Correct!", IO.ANSI.reset()])
391+
392+
{:incorrect, help_text} when is_binary(help_text) ->
393+
IO.puts([IO.ANSI.red(), "Incorrect: ", IO.ANSI.reset(), help_text])
394+
395+
_ ->
396+
IO.puts([IO.ANSI.red(), "Incorrect.", IO.ANSI.reset()])
397+
end
284398
```
285399

286400
## Resource

modules/grading_client/priv/answers.exs

+27-2
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,33 @@ graphql_questions = [
4545
}
4646
]
4747

48+
elixir_security_questions = [
49+
%{
50+
question_id: 1,
51+
answer: %ArgumentError{
52+
message:
53+
"errors were found at the given arguments:\n\n * 1st argument: not an already existing atom\n"
54+
},
55+
help_text: "Read the Prevention section above."
56+
},
57+
%{
58+
question_id: 2,
59+
answer: %BadBooleanError{
60+
term: :access_denied,
61+
operator: :or
62+
},
63+
help_text: "Read the Prevention section above."
64+
},
65+
%{
66+
question_id: 3,
67+
answer: :private,
68+
help_text: "Read the documentation for :ets.new/2"
69+
}
70+
]
71+
4872
List.flatten([
4973
to_answers.(OWASP, owasp_questions),
50-
to_answers.(SDLC, part3_questions),
51-
to_answers.(GRAPHQL, graphql_questions)
74+
to_answers.(SDLC, sdlc_questions),
75+
to_answers.(GRAPHQL, graphql_questions),
76+
to_answers.(ELIXIR_SECURITY, elixir_security_questions)
5277
])

0 commit comments

Comments
 (0)