Password. Storage. Is. Bad.
I got into a really dumb argument with someone who was saying that it was best to store user passwords encrypted with PGP. I’m tired of explaining to people why doing stuff like this is a bad idea, so I’m just gonna write this here as a thing I can link to people when they suggest ideas like that.
Lets get something out of the way first, keeping your users’ passwords safe is important. Even though we all know we should be using password managers, with a randomly generated password for each site, the vast majority of users aren’t doing that (yet). If you let a user’s password out, you don’t know what other accounts belonging to that person it might work on, whether it’s some random forum account they’ve forgotten about, their online banking, or worse, their primary email account. It doesn’t matter whether you have 2FA, or you have advanced fraud detection, no one cares. Handling user passwords improperly is negligent, insecure, dumb, and just plain irresponsible.
So, on to what NOT to do with your users’ passwords:
First off, the really naive solution of just storing the users’ passwords in plaintext. This is obviously a bad idea, since if any sort of data leak happens, then, well, all them passwords are out.
“So,” you might be thinking, “why not just encrypt all the passwords?” Well, while it’s better than nothing (it would protect against SQLi, assuming the keys aren’t stored in the database), along with probably at least a few other scenarios. However, if your box gets completely pwned, you’re still SOL.
“Well then,” you’re saying, “just hash all of the passwords then.” Finally, you’re starting to get on the right track. Your main issue now is that your hashes are gonna be identical to every other site out there that just hashes the plain password. In fact, in a lot of cases, you can even google just the hash, and it’ll return at least one site telling you the matching input. Even if that weren’t the case, you’re still open to rainbow table attacks.
The solution to this is to “salt” your hashes, in effect prepending some data to the password before hashing. Before you go running off to do that though, there’s one big pitfall: you can’t use one static salt for all the users on your site. Here’s why: if two of your users share the same password, they’re gonna have the same hash in your database. This means an attacker could just do all the cracking in one go (as opposed to having to crack every hash individually, more on that in a bit).
So, now, on to what to do:
You should be taking the user’s password, hashing it with a unique, per-user salt (that’s stored alongside the hash), using a modern hash algorithm or key derivation function.
Or, even better, use a library/framework that abstracts all of this away from you.