So there is a decent amount of “flack” information out there about how to properly and securely save passwords via PHP to your database. I wonder if this is partially because so many years of old out dated answers and discussions have muddled the effectiveness of google, or if to many people it is just not clear or sure. No matter the reasons I decided to share some of the best ways to deal with passwords.
Ten years ago most people would answer this quite quickly with “use MD5” but as that has become less secure, computers have become more powerful, and hacks have become more advanced, using MD5 is not really a good idea. Some now would say use SHA256 or even SHA512, but it’s not just a simple, replace MD5 with a more secure HASH function ether. While currently that might work, it is not very future friendly as ASCII cracking machines get more powerful, in a few years you will be in the same boat. Also this does not solve any of the other issues with more advanced attacks like rainbow tables.
So what is the answer? Salts. You need to use a salt before you HASH or maybe better encrypt your password. A salt simplified is just a random string you add to your password. The key to making this work, and more secure though is making sure the salt is UNIQUE to each users password. It also needs to be really random, and not a pattern, so don’t just use the users email, or birthday.
A SALT has to be the following to be secure:
- Unique to each user.
- Random(use one of the random secure libraries out there for PHP)
- Long, you want it long enough to take advantage of Hash or encryption functions. So if using SHA256 you want it at least 36 char long.
Ok so you have a salt, now how do you save it? This is a great question that takes some thought. What if someone uses SQL injection, and gets your user table? To secure against this, you might want to consider keeping the salt in another table, or even better yet, in another database. What if your databases are all compromised, it could happen right? That’s where I use a second SALT. This one, is a site specific one, one that is long, very random, but shared to all on the site via an include statement. Ideally you want this to be in a directly none of your ssh or sftp accounts have access too, so if your file system is compromised, it will not be.
So this looks something like this:
$securePassword = hash($serverSalt . $password . $randomSalt);
So which hash do you use? SHA512? Do use blowfish or whirlpool? crypt()? User your own homemade or combination?(Ok never make your own, as you could make some very insecure hash, you want something peer reviewed.) We could talk for hours on which hash is better, why and even if you should use a hash or encrypt it. The fact is, if you use the salt method, even MD5 will be decently secure. Still you want to pick one that is not flawed, works well, and will not require you to make every user change their password when a new hack is found… That’s where the next part comes in.
Those of you reading this probably were wondering why I have not mentioned this sooner, but to answer some of the issues mentioned above, PHP now includes a password tool set via the password_hash() and password_verify() functions. You will need PHP 5.5 or a shim to use this easier way. Like the names imply, one will hash, while the other will check that it matches. You can read the manual pages for more details, but here are the key reasons why it rocks:
- Self salted, the salt is stored in the hash(not 100% ideal, but convenient). You can also supply your own salt.
- Hash agnostic, you can switch at any point what hash you use(it supports any that you currently have set up in php), and not break past encryptions. You can even have it upgrade or change past hashes. It stores this info also in the string.
- Support for encryption, so say you don’t want to use SHA, and would rather use bcrypt? No problem, it will even let you set variables, like hardness on it, and change that later if your server gets an upgrade and can handle more. (I know crypt did this before too, but what makes this handy is it can hash one password, then crypt the next and store them in the same table.)
- Future friendly, you can use the same syntax, and the backend will be updated and secure.
I would recommend you take this one step further like I do. I combine the above salting steps, different table salt, and site wide, before I use the password_hash function. So it looks something like this(like not exactly):
So there you have it, how to save your passwords in PHP. But you don’t have to take my word for it, in fact, when it comes to security NEVER take the word of just one expert, professor, or website. Always read as much as you can on it, and fully understand how and why it works before writing your own code.
Some further reading to get you started: