I took time recently to read up on best methods for generating and storing user password hashes. The ‘base’ I often use for websites, in PHP, hasn’t been updated in a while and needed some updating on the login side of things. This article at crackstation.net was pretty much everything I used while updating how my base hashes user passwords and generates and stores the salts.
Previously, I was using the same, static salt for everyone, but found that to be a less than optimal practice, from a security standpoint. Everything I did was pretty heavily based on the PHP source provided in the crackstation.net piece.
Using a random salt means that you need to keep track of it somehow, and that’s usually done by saving the salt in the database, along with the password hash and other user info. But, if your database is compromised, the salt used in creating the password hash is readily available for the attacker. And that’s not a good thing.
So, in addition to the stuff described in the Crackstation.net article, I also use a static, but still random string that gets appended to each random salt. Now, if my database is compromised, but my filesystem is still secured, attackers won’t have the entire salt. The static string that we add to the random salt should only be accessible from our PHP source, which is on the still secure filesystem.
If you can, use a third-party library for password hashing, like phpass, which is used in projects like WordPress and Vanilla. It’s very popular, and for good reason.
Another good library for passwords in PHP would probably be PHP Password Library. I’ve never used it myself, but it looks like it’d be really easy to integrate into existing code, and can be installed via Composer.
Also, if you’re able to run PHP 5.5.x, you can make use of the new password hashing functions, password_hash() and password_verify(). This article at Sitepoint gives a good overview of the new functions.
If you’re on an older version of PHP (anything below PHP 5.5.0) and would like to use the new password hashing functions, you should look at ircmaxwell/password_comapt on github. It provides forward-compatibility with the password_* functions found in PHP 5.5.
So, there’s no shortage of good options for helping out with password hashing. And if you do need to roll your own, you can use a function like openssl_random_pseudo_bytes() or mcrypt_create_iv to generate the salt.
I’m generating random salts using openssl_random_pseudo_bytes() and using MySQL’s sha2 function for password hashing. sha2() was added in MySQL 5.5.5, so it probably won’t be available to you if you’re using an earlier version. Although I believe many linux distributions have a patched version.
Did I mess something up? Please let me know if I’ve missed something or if I’m just totally off base somewhere. Comments are open.
Edit: As Matt noted in the comments, sha2 isn’t a very good choice, so I’m
going to use now using the password_comapt library, hello bcrypt.
Well, now what?
Work with Me
I'm available for hire and always taking new clients, big and small. Got a project or an idea you'd like to discuss? Startup plan but no developer to make it happen? Just get in touch, I'd love to see if I can help you out!
Leave some Feedback
Got a question or some updated information releavant to this post? Please, leave a comment! The comments are a great way to get help, I read them all and reply to nearly every comment. Let's talk. 😀
3 thoughts on “Password Hashing in PHP, The Right Way™”
Salted SHA-2 is not a great choice; the fundamental problem is that computing it is designed to be fast – note that there’s been a TON of work put into doing SHA-256 very fast indeed, as it’s the core of the Bitcoin mining algorithm.
Functions that are specifically engineered to be one-way *and* time-consuming are a better choice; bcrypt is popular, scrypt and PBKDF2 are also considered highly.
Thanks Matt! I’ll look at using bcrypt, since I think that’s the default in phpass. I’ll update post, too.
There’s no real benefit to using a site-wide static salt, see: http://blog.ircmaxell.com/2012/04/properly-salting-passwords-case-against.html
Also, salts are not meant to be a secret. Your comment about them being compromised if the database is compromised doesn’t make them less secure. Modern password hashing functions actually store the salt as part of the generated hash.
A salt exists for solely one purpose: to prevent the creation of rainbow tables against your passwords. http://en.wikipedia.org/wiki/Rainbow_table Salts do not need to be cryptographically secure, they just need to be unique per password.
The Right Way(tm) to store passwords in PHP is to use the PHP5.5 built in methods, or the compat library you mentioned. But that makes for a very short article.