You can see a cheatsheet here:
As today everyone doing password hashing knows, or with little Googling knows, they need to use a key stretching algorithm. Doing just hash is not enough (https://crackstation.net/hashing-security.htm).
Randomly generated Keys, e.g. 256 bits api keys, don't require Key Stretching, if the key is generated using entropy and a Secure Random algorithm.
This post is about what you should input to the [password] hashing algorithm.
First of all is the secret, e.g. the Password, API Key, access_key.
Most password hashing algorithms already include a salt, just make sure the algorithm and the implementation you choose does.
What's mostly forgotten is to include an association of the secret to the entity. e.g. the user, device, API.
Lets simulate the case an attacker can exploit an SQL injection vulnerability with write capabilities to the DB and table where the hashed secrets are.
If it's a public service (e.g Facebook), they can create an account, and then replace any victims hashed password with the one generated for his, the attacker, user.
If it's a public service (e.g Facebook), they can create an account, and then replace any victims hashed password with the one generated for his, the attacker, user.
The recommendation is to add the identifier (or identifiers, e.g. in case the user can login with username or email) of the entity as an input to the algorithm.
In case your identifier can change, like email, you need to consider it for the email change flow, which will probably require the user to input the password to confirm.
With this additional input only protected against hash swaps being successful, but we still haven't protected password hashes from being replaced by a malicious actor.
The attacker could still read the salt, identifier and use his password to generate the password hash (yes, they would still need to know the algorithm used, the amount of rounds, and how are inputs combined, the first two are usually stored with the password hash, and the latter can be easily guessed/brute forced).
The last input we will add is what's called the Pepper, it's a secret which is the same for all secrets, and it's not stored in the DB. It's usually managed by an HSM, AWS KMS, Hashicorp Vault, Square Keywhiz, etc.
While this Key remains secret it will be practically impossible (if the Key is properly generated and at least 128 bits Secure Random.) for an attacker to brute force the password hash, or to generate a password hash.
Optionally instead of using this Pepper as an input to the [password] hash algorithm you could opt to encrypt them [password] hash. The added value is that in case the Pepper is leaked (but maybe the DB is not), you could rotate it in the backend.
Since you will potentially include many inputs to a password hashing algorithm, e.g 8 word password, e-mail, pepper, make sure the implementation you are using doesn't truncate input, as Bcrypt does, limiting to 72 bytes, resulting remainder bytes to be truncated. If it's truncating hashing should solve the issue:
1. Password_Hash(Salt, SHA256(Pasword, Pepper, e-mail) ) )
2. AES(Pepper, Password_Hash(Salt, SHA256(Pasword, e-mail) ) )
3. AES(Pepper, HMAC(SHA256, API_Key, customer_id) )
*the use of HMAC is not strictly needed, it's just to rule out hash length extension attack vectors.
Interesting article, though I don't see them mention entity association.
https://blogs.dropbox.com/tech/2016/09/how-dropbox-securely-stores-your-passwords/
No comments:
Post a Comment