Skip to content

Commit de6954d

Browse files
authored
Add Sensitive Data Exposure Section (#51)
1 parent 4981c4b commit de6954d

File tree

1 file changed

+65
-0
lines changed

1 file changed

+65
-0
lines changed

modules/5-elixir.livemd

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ But even the dullest blades can hurt someone! This module goes over Elixir speci
1717
* [Untrusted Code](#untrusted-code)
1818
* [Timing Attacks](#timing-attacks)
1919
* [Boolean Coercion](#boolean-coercion)
20+
* [Sensitive Data Exposure](#sensitive-data-exposure)
2021

2122
## Atom Exhaustion
2223

@@ -219,4 +220,68 @@ user_input = "some_string_which_obviously_isnt_the_same_as_the_password"
219220
# if SecurityCheck.validate(user_input, password) || raise(SecurityCheck) do :you_let_a_baddie_in end
220221
```
221222

223+
## Sensitive Data Exposure
224+
225+
### Description
226+
227+
Sensitive data is any information that should be out of reach from all outsiders unless they have permission to access it, which in most cases would be considered "confidential data". Some examples of sensitive data are PHI (Protected Health Information) or PII (Personally Identifiable Information).
228+
229+
While it's obvious that we don't want data of this nature to get exposed, let's walk through some of the common instances in which it _can_ occur while using Elixir and how to prevent it from happening!
230+
231+
### Prevention
232+
233+
## Wrapping
234+
235+
Exceptions may result in console or log output that includes a stack trace. Mostly a stack trace shows the module/function/arity and the filename/line where the exception occurred, but for the function at the top of the stack the actual list of arguments may be included instead of the function arity.
236+
237+
To prevent sensitive data from leaking in a stack trace, the value may be wrapped in a closure: a zero-arity anonymous function. The inner value can be easily unwrapped where it is needed by invoking the function. If an error occurs and function arguments are written to the console or a log, it is shown as `#Fun<...>` or `#Function<...>`.
238+
239+
Secrets wrapped in a closure are also safe from introspection using [Observer](https://elixir-lang.org/getting-started/debugging.html#observer) and from being written to crash dumps.
240+
241+
### <span style="color:blue;">Example</span>
242+
243+
```elixir
244+
wrapped_secret = fn -> System.get_env("SECRET") end
245+
```
246+
247+
## Stacktrace Pruning
248+
249+
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
250+
251+
### <span style="color:blue;">Example</span>
252+
253+
```elixir
254+
def encrypt_with_secret(message, wrapped_secret) do
255+
ComeCryptoLib.encrypt(message, wrapped_secret.())
256+
rescue
257+
e -> reraise e, prune_stacktrace(System.stacktrace())
258+
end
259+
260+
defp prune_stacktrace([{mod, fun, [_ | _] = args, info} | rest]),
261+
do: [{mod, fun, length(args), info} | rest]
262+
263+
defp prune_stacktrace(stacktrace), do: stacktrace
264+
```
265+
266+
## ETS Tables
267+
268+
[ETS tables](https://elixir-lang.org/getting-started/mix-otp/ets.html) are commonly used as a go to caching mechanism in-app. But did you know that they can be declared as private (through the use of the `:private` option when instantiating them)?
269+
270+
This prevents the table from being read by other processes, such as remote shell sessions. Private tables are also not visible in Observer.
271+
272+
### <span style="color:red;">Quiz</span>
273+
274+
**We have decided that we do not want this ETS table to be read from other processes, so try making it private:**
275+
276+
```elixir
277+
secret_table = :ets.new(:secret_table, [:public]) # ONLY EDIT THIS LINE
278+
:ets.info(secret_table)[:protection]
279+
```
280+
281+
## Resource
282+
283+
1. https://erlef.github.io/security-wg/secure_coding_and_deployment_hardening/sensitive_data.html
284+
285+
286+
222287
[**<- Previous Module: GraphQL Security**](./4-graphql.livemd) || [**Next Module: Cookie Security ->**](./6-cookies.livemd)

0 commit comments

Comments
 (0)