Tutorial: The Best Way to Store Passwords in a Database
Codementor PHP Expert Ben Edmunds sat down with us during Office Hours to share his experience in PHP security. One of the questions asked was the best and correct way to store passwords in a database nowadays.
The text below is a summary done by the Codementor team and may vary from the original video and if you see any issues, please let us know!
What is the Best or Most Correct Way to Store Passwords in a Database?
Consider this: If I had access to your database, will there be a way for me to figure out what the passwords are? For example, if your passwords use a hash with no salt, such as a hash using MD5, then I know I can run a program and eventually figure out what the passwords. Or if it’s a reversible encryption because it’s not a hash, as in you can encrypt and decrypt it—that is bad. You should never be able to figure out what the password is, and it should be a one-way thing so all you can see is the hash.
If you’re on a newer version PHP, I would totally recommend using the native PHP functions now, which is also known as bcrypt. It will use salt and hash the password in a one-time use hash and keep your passwords secure, as it won’t expose plain text to your database.
Of course, you’d want to be able to recreate that hash, so you’d store the unique salt, which is a random string thrown into the password so it’s going to be a different hash for each person, even if they have the same password.
On that note, if you have MD5 as your hashing algorithm, the best way to upgrade that is to invalidate all those passwords, and then rehash it the next time the person logs in. In other words, set a new flag in the database that says MD5 or bcrypt, and check the flag the next time a user logs in. If the flag says MD5, rehash it with bcrypt, re-save that to the database, and then set that user’s flag to bcrypt.
However, problems may arise if you have a lot of users and you have a big database, but the users don’t log in frequently or don’t have a lot of expiration tokens. After all, if a hacker somehow compromised your database, you don’t want to lose years of users’ passwords for the users who haven’t logged in recently to have their hash converted. A solution around that to actually just bcrypt your actual MD5 hashes and end up with MD5 plus bcrypt passwords. It will be a little slower, but actually slow is good in login because the longer something takes, the harder it will be for someone else to get around your security and hack it. Good hashing algorithms such as bcrypt are designed to have a cost factor, so it won’t be super fast, which makes it take more time to crack.
How Big of a Deal is it to Upgrade from SHA-512 to Bcrypt?
SHA-512 is not horribly bad, since I can’t remember if there are currently any known exploits fight off the top of my head as long as you’re using a valid, unique salt. If you’re using it without salt, SHA-512 is horrible and you should go change it today. You should probably just do the bcrypt hashing of that hash.
However, as far as I’m aware, SHA-512 is still safe, but just not preferred because the algorithm is not as complex, so it’s not as good for the future.
How Do Organizations like Facebook Keep Track of Previous Passwords Without Storing All that Data?
I don’t know how Facebook in particular does it, but I know how I’ve done it in the past. I would store the salt on the password, and then whenever you go to change your password, I will just run that again with the same salt and see if the hash matches any of your previous passwords.
For example, if you have a database table with the last five passwords (hashes) and the user logins in to change that password, you just rerun it with the same salt and check to see if it exists in the same table for that user ID and that hash. Therefore, you still don’t know what the password was, since you don’t ever want to know what it was, but by rehashing with the same salt, you can tell if it matches previous hashes you have stored.
One of our viewers, Jonathan Reinink, posted a good link in the chat. If you’re on less than php 5.5, use IRC Maxell. It has a password compat library that will implement the same core functionality for you in a library form, so if you’re between 5.3.7 and 5.5, you can use this for password hashing and verification functions.
Other posts in this series with Ben Edmunds:
- Tutorial: Building Modern & Secure PHP Applications
- Should PHP developers Also Handle DevOps?
- Q&A With PHP Security Expert Ben Edmunds
- The Most Common Reason a Hacker Attacks Your PHP Applications
Need Ben’s help? Book a 1-on-1 session!