Basically, I’d like to make the following code safe from timing attack:
api_keys = %{
"secret1" => [1, 2, 3],
"secret2" => [1, 2, 3],
}
def api_endpoint(...) do
Map.fetch(api_keys, conn.assign.api_keys)
|> case do
{:ok, resources} -> "you got access"
:error -> "sorry, no access"
end
end
Usually, I would pass the provided secrets into a password hashing function, this is actually a cache to make an API very fast, so I cannot introduce an overhead of something like argon2 or similar.
I feel like that obscures the plain equality check, but it seems like that’d still be vulnerable. I would think you’d want to replace == with a constant time equality checker like Plug.Crypto.secure_compare/2.
Erlef’s page on timing attacks suggests newer versions of Erlang have a crypto:equal_const_time/2, but I’m not seeing it or finding anything about it.
Instead of accessing by API key, you can access by API client and then compare the application password with a secure function such as Plug.Crypto.secure_compare/2.
Are you issuing these API keys? If you have control of the key structure one solution would be doing more of an id + secret pairing (whether that’s multiple params, or combined into a string, or like basic auth), looking up the key by id, then doing a timing-safe compare for the secret.