Password Auth
Recently I have started contributing to Kanidm. And I got to know a lot about how to do password auth properly.
Using password alone to authenticate is not that secure nowadays, so it is always recommended to turn on MFA, as explained here by Microsoft and NIST.
However, password login is not going away anytime soon. So we still need to do our best to protect the password login process.
See Firstyear’s post to check how we can improve password login security by:
- Using generated strong password
- Using the
zxcvbn
library to check password quality - Password blacklisting to reject known exploited passwords
Other than that, we also need to store password securely in the database.
How to store password??
Hash function
To store password securely would mean that even if attacker obtain the hashed password text, they cannot reverse the hash to get the password in plaintext. (Sidenote: hashing is not encrypting, one is irreversible and one is reversible)
One way to attack hashed password is brute-force: guessing the password and check if it is correct (dictionary attack). To make this attack ineffective, we should aim to slow down the attacker when try to guess the password.
In general, hashing functions like bcrypt, PBKDF2 and scrypt, applies the hashing function in many iterations and makes the computational cost much higher. If attacker has to guess a password, they have to run the hashing function, say, 10000 times to get the final hashed password. This makes calculating each guess much longer thus make brute-forcing password ineffective.
Using SHA-1/SHA-256/SHA-512 could hash the password, but they are less “secure” since it is only 1 iteration. Also note that the bit length in SHA: 1/256/512 doesn’t change the security very much in terms of dictionary attack.
Salt and Rainbow table
From wiki: “A rainbow table is a precomputed table for caching the output of cryptographic hash functions, usually for cracking password hashes. Tables are usually used in recovering a key derivation function (or credit card numbers, etc.) up to a certain length consisting of a limited set of characters.”
To solve that problem, we can use salt! Salt is another phrase that we add to our hashing function, it looks like this: hash(password_plaintext, salt)
.
Salt is stored as plaintext in the database. We can generate a salt for each password, which would mean: even if we are using the same plaintext password, the generated hashes are going to be different due to having different salts.
How does that help prevent rainbow table attack? It makes the rainbow table pre-computed values useless. Now attackers can try to crack it with the salt and hashed password, but that would require brute-forcing again. :)
Application-level rate-limiting
We can also implement a rate-limiting mechanism on application-level. We can build it according to our needs. For example, we could limit login attempt to 5 times in 1 minute, or enforce MFA if login is done from a different device/IP.
References
- https://security.stackexchange.com/questions/52041/is-using-sha-512-for-storing-passwords-tolerable
- https://www.maketecheasier.com/password-hashing-encryption/
- https://stackoverflow.com/questions/326699/difference-between-hashing-a-password-and-encrypting-it