diff --git a/modules/2-owasp.livemd b/modules/2-owasp.livemd
index 4b31bf5..c61ea3f 100644
--- a/modules/2-owasp.livemd
+++ b/modules/2-owasp.livemd
@@ -1,3 +1,5 @@
+
+
# ESCT: Part 2 - OWASP
```elixir
@@ -101,25 +103,29 @@ Notable CWEs included are CWE-259: Use of Hard-coded Password, CWE-327: Broken o
_Please uncomment the function call that you believe is correct._
-
+
```elixir
result =
- defmodule PasswordCompare do
- def option_one(password, md5_hash) do
- case :crypto.hash(:md5, password) == md5_hash do
- true -> :entry_granted_op1
- false -> :entry_denied_op1
+ (
+ defmodule PasswordCompare do
+ def option_one(password, md5_hash) do
+ case :crypto.hash(:md5, password) == md5_hash do
+ true -> :entry_granted_op1
+ false -> :entry_denied_op1
+ end
end
- end
- def option_two(password, bcrypt_salted_hash) do
- case Bcrypt.verify_pass(password, bcrypt_salted_hash) do
- true -> :entry_granted_op2
- false -> :entry_denied_op2
+ def option_two(password, bcrypt_salted_hash) do
+ case Bcrypt.verify_pass(password, bcrypt_salted_hash) do
+ true -> :entry_granted_op2
+ false -> :entry_denied_op2
+ end
end
end
- end
+
+ PasswordCompare.option_two("users_password", bcrypt_salted_hash)
+ )
case GradingClient.check_answer(OWASP, 1, result) do
:correct ->
@@ -133,6 +139,18 @@ case GradingClient.check_answer(OWASP, 1, result) do
end
```
+
+
+```
+Correct!
+```
+
+
+
+```
+:ok
+```
+
## Injection
@@ -257,7 +275,7 @@ _Please change the atom below to the name of the vulnerable package installed in
_HINT: Check the changelogs for each dependency._
-
+
```elixir
result =
@@ -266,7 +284,7 @@ result =
Kino.Input.select("Answer",
ecto: "Ecto v2.2.2",
nx: "Nx v0.5.0",
- plug: "Plug v1.3.2"
+ plug: "Plug v1.19.3"
)
Kino.render(answer)
@@ -285,6 +303,18 @@ case GradingClient.check_answer(OWASP, 2, result) do
end
```
+
+
+```
+Correct!
+```
+
+
+
+```
+:ok
+```
+
## Identification and Authentication Failures
@@ -415,4 +445,18 @@ case HTTPoison.get(user_inputted_url) do
end
```
+
+
+```
+This is the IP belonging to your Livebook instance:
+2607:fea8:1421:2910:54be:80ef:2fdb:53d7
+
+```
+
+
+
+```
+:ok
+```
+
[**<- Previous Module: Introduction**](./1-introduction.livemd) || [**Next Module: Secure SDLC Concepts ->**](./3-ssdlc.livemd)
diff --git a/modules/3-ssdlc.livemd b/modules/3-ssdlc.livemd
index 276c1e2..099b38e 100644
--- a/modules/3-ssdlc.livemd
+++ b/modules/3-ssdlc.livemd
@@ -1,3 +1,5 @@
+
+
# ESCT: Part 3 - Secure SDLC Concepts
```elixir
@@ -47,10 +49,10 @@ A very easy way to prevent secrets being added to files is to access them via En
_Use `System.get_env/1` on line 2._
-
+
```elixir
-result = super_secret_password = "p@ssw0rd"
+result = super_secret_password = System.get_env("envar_secret")
case GradingClient.check_answer(SDLC, 1, result) do
:correct ->
@@ -64,6 +66,18 @@ case GradingClient.check_answer(SDLC, 1, result) do
end
```
+
+
+```
+Correct!
+```
+
+
+
+```
+:ok
+```
+
## Making Secret Rotation Easy
### Description
diff --git a/modules/4-graphql.livemd b/modules/4-graphql.livemd
index 19e716c..d661033 100644
--- a/modules/4-graphql.livemd
+++ b/modules/4-graphql.livemd
@@ -1,3 +1,5 @@
+
+
# ESCT: Part 4 - GraphQL Security
```elixir
@@ -88,6 +90,18 @@ case GradingClient.check_answer(GRAPHQL, 1, result) do
end
```
+
+
+```
+Correct!
+```
+
+
+
+```
+:ok
+```
+
## Error Disclosure
### Description
@@ -134,6 +148,18 @@ case GradingClient.check_answer(GRAPHQL, 2, result) do
end
```
+
+
+```
+Correct!
+```
+
+
+
+```
+:ok
+```
+
### Resources
1. https://github.com/OWASP/API-Security/blob/master/2019/en/src/0xa7-security-misconfiguration.md
diff --git a/modules/5-elixir.livemd b/modules/5-elixir.livemd
index a3afc69..d8f7eea 100644
--- a/modules/5-elixir.livemd
+++ b/modules/5-elixir.livemd
@@ -1,3 +1,5 @@
+
+
# ESCT: Part 5 - Elixir Security
```elixir
@@ -50,7 +52,7 @@ Beware of functions in applications/libraries that create atoms from input value
_You should get a `true` result when you successfully fix the function._
-
+
```elixir
result =
@@ -58,7 +60,7 @@ result =
malicious_user_input = UUID.uuid4()
try do
- malicious_user_input |> String.to_atom()
+ malicious_user_input |> String.to_existing_atom()
rescue
e -> e
end
@@ -76,6 +78,18 @@ case GradingClient.check_answer(ELIXIR_SECURITY, 1, result) do
end
```
+
+
+```
+Correct!
+```
+
+
+
+```
+:ok
+```
+
## Serialization and Deserialization
### Description
@@ -121,6 +135,12 @@ textfield_value = Kino.Input.read(name)
"Hello, " <> result
```
+
+
+```
+"Hello, Marius"
+```
+
**BONUS QUESTION**: How would you go about securing the code above?
Hint: Deleting it _entirely_ is a fair approach 😉
@@ -181,7 +201,25 @@ user_input = "HASH_OF_asdfasdf"
Benchwarmer.benchmark(fn -> Susceptible.compare(user_input, password) end)
Benchwarmer.benchmark(fn -> Constant.compare(user_input, password) end)
-# IO.puts(:comparison_ran)
+IO.puts(:comparison_ran)
+```
+
+
+
+```
+*** #Function<43.113135111/0 in :erl_eval.expr/6> ***
+1.3 sec 8M iterations 0.17 μs/op
+
+*** #Function<43.113135111/0 in :erl_eval.expr/6> ***
+1.1 sec 8M iterations 0.14 μs/op
+
+comparison_ran
+```
+
+
+
+```
+:ok
```
## Boolean Coercion
@@ -213,7 +251,7 @@ The latter will raise a `BadBooleanError` when the function returns `:ok` or `{:
_Uncomment the if statement that uses the correct boolean comparison._
-
+
```elixir
result =
@@ -234,6 +272,9 @@ result =
:ok
try do
+ if SecurityCheck.validate(user_input, password) or raise(SecurityCheck) do
+ :you_let_a_baddie_in
+ end
rescue
e -> e
end
@@ -251,6 +292,18 @@ case GradingClient.check_answer(ELIXIR_SECURITY, 2, result) do
end
```
+
+
+```
+Correct!
+```
+
+
+
+```
+:ok
+```
+
## Sensitive Data Exposure
### Description
@@ -275,6 +328,12 @@ Secrets wrapped in a closure are also safe from introspection using [Observer](h
wrapped_secret = fn -> System.get_env("SECRET") end
```
+
+
+```
+#Function<43.113135111/0 in :erl_eval.expr/6>
+```
+
## Stacktrace Pruning
Another approach, useful in functions that call the standard library (e.g. crypto) or other functions that do not support wrapping secrets in a closure, is stripping argument values from the stack trace when an exception occurs. This can be done by wrapping the function call(s) in a try … catch expression (Erlang) or adding a rescue clause to a function body (Elixir), and stripping the function arguments before re-raising the exception
@@ -304,12 +363,12 @@ This prevents the table from being read by other processes, such as remote shell
**We have decided that we do not want this ETS table to be read from other processes, so try making it private:**
-
+
```elixir
result =
(
- secret_table = :ets.new(:secret_table, [:public])
+ secret_table = :ets.new(:secret_table, [:private])
:ets.info(secret_table)[:protection]
)
@@ -325,6 +384,18 @@ case GradingClient.check_answer(ELIXIR_SECURITY, 3, result) do
end
```
+
+
+```
+Correct!
+```
+
+
+
+```
+:ok
+```
+
## Resource
1. https://erlef.github.io/security-wg/secure_coding_and_deployment_hardening/sensitive_data.html
diff --git a/modules/6-cookies.livemd b/modules/6-cookies.livemd
index ec4f5a4..ace58fd 100644
--- a/modules/6-cookies.livemd
+++ b/modules/6-cookies.livemd
@@ -181,12 +181,18 @@ In the Phoenix Framework, you would use functionality found within the [Plug lib
_Fill out the `put_resp_cookie/4` function arguments with the settings outlined in the previous section, no other code changes should be necessary._
-
+
```elixir
result =
(
- cookie_name = "CHANGE_ME"
+ cookie_name = "__Host-bogus-cookie"
+
+ conn =
+ Plug.Conn.put_resp_cookie(
+ conn,
+ cookie_name,
+ <<0::8, 42::8>>, path: "/", secure: true, http_only: true, same_site: "Strict")
cookie =
conn
diff --git a/modules/7-anti-patterns.livemd b/modules/7-anti-patterns.livemd
index 3904a6d..41a48dc 100644
--- a/modules/7-anti-patterns.livemd
+++ b/modules/7-anti-patterns.livemd
@@ -1,3 +1,5 @@
+
+
# ESCT: Part 7 - Security Anti-Patterns
```elixir
@@ -52,6 +54,12 @@ end
A.b([3, 4, 5, 2, 1])
```
+
+
+```
+[1, 2, 3, 4, 5]
+```
+
### Example - Redux
How about this, same exact function before - but this time with human readable names. Does it make it easier or harder to understand what the function is doing? Technically the code is still obfuscated...
@@ -69,6 +77,12 @@ end
Penguin.slide([3, 4, 5, 2, 1])
```
+
+
+```
+[1, 2, 3, 4, 5]
+```
+
### Quiz
**What sorting algorithm is the module above using?**
@@ -102,6 +116,18 @@ case GradingClient.check_answer(ANTIPATTERNS, 1, result) do
end
```
+
+
+```
+Correct!
+```
+
+
+
+```
+:ok
+```
+
## Frontend Authorization Checks
### Description
diff --git a/modules/8-cicd.livemd b/modules/8-cicd.livemd
index 729ce41..d59675a 100644
--- a/modules/8-cicd.livemd
+++ b/modules/8-cicd.livemd
@@ -1,3 +1,5 @@
+
+
# ESCT: Part 8 - CI/CD Tools
```elixir
diff --git a/modules/9-secure-road.livemd b/modules/9-secure-road.livemd
index 2dd95d8..a437070 100644
--- a/modules/9-secure-road.livemd
+++ b/modules/9-secure-road.livemd
@@ -1,3 +1,5 @@
+
+
# ESCT: Part 9 - The Secure Road
```elixir