(This post was updated in March 2018 after I requested comments on Twitter and was informed of a newer algorithm.)
I made a post a while back about how to check if a user’s password is secure from the programmer’s perspective, but looking at it now, I realized I don’t cover a key concept, and I’ve learned about an additional measure that I really should have had on the list.
How to store passwords?
The number 1 most important thing to do is to NEVER store passwords. Instead, you use an algorithm to store a hash generated from a password. Why? In case you get hacked. If your database is downloaded, and it has user passwords, even if you repair any damage or stop the hack, the passwords are out there! But if you use hashes instead, they can’t be used to login.
How you hash matters though. If you use something like MD5, that’s trivial to crack these days. SHA-1 is a bit more secure, but still has been destroyed in usefulness for security. Which algorithm(s) should you be using?
- bcrypt: The current de-facto algorithm for password hashing. It can be changed the strength of the algorithm to create stronger hashes even if computers get faster.
- scrypt: Builds upon bcrypt by focusing on calculations that are harder to do on specialized hardware. It also can be changed to create stronger hashes, but the factor used to do this is exponential.
- Argon2*: Won the Password Hashing Competition in 2015**, the only reason it’s not on the top of this list is that it is relatively new and not as proven as scrypt/bcrypt. (The biggest weakness with bcrypt at the moment is that it can be relatively effectively attacked with GPUs/FPGAs/ASICs, which scrypt and Argon2 protect against by increasing how much memory is required to compute a password hash.)
- PBKDF2: Wasn’t actually intended to be used for security, but is rather slow, which makes for a good hash algorithm. (A big part of hash security is using a slow algorithm.)
It is most often recommended to use bcrypt as it is the most tested and known secure algorithm. It will probably be replaced by scrypt when scrypt has been more thoroughly tested and if vulnerabilities are found in bcrypt. PBKDF2 should really only be used if for some reason you can’t use the other two. If you want to use something else, don’t.
What kind of passwords should be allowed?
This was the whole point of the other post, and the first three items are almost identical:
- Must not contain more than 6 occurrences of the same character.
- Must be at least 12 characters long.
- Must not be equal to your username, your email address, the site’s name, the site’s URL.
- Must not be equal to the 10,000* most common passwords.
The change is to say you should have 12 character or longer passwords, and the addition is checking against the most commonly used passwords. The first measure is because computers are always getting better at cracking passwords, and cheaper. The second is because the first two rules don’t completely stop you from using commonly known passwords like
qwertyuiop (actually it does with the second one only being 10 characters :P).
* I say 10,000, but the list really should be just whatever most common passwords list you can get ahold of. This is something I need to research further myself.
Some Sources / Further Reading
These primarily relate to Argon2 since that is what I most recently researched when editing this post.
- Password Hashing Competition
- An brief explanation of results from PHC & notes about attacks against Argon2. (This was another reason I put it lower on the list, though I am not an expert by any means, so I could be completely unjustified.)
- Several comparisons and discussion about configuring these algorithms correctly.
- A bit of arguing and discussion about bcrypt and PBKDF2.
- More discussion about Argon2.
- libsodium is a library for doing crypto stuff that I’ve heard many people I would trust with this kind of thing recommend. I haven’t looked too much at it myself, but I would confidently pass their recommendation along.
* Was added in March 2018 after some further research into the subject.
** I found a couple of sources claiming it was in 2015, but also one that said 2013. I’m not sure which is correct.