Historically, password security in PHP has been a bit slippery, requiring a measures of knowledge and care. Aiming to changes that, PHP 5.5 introduces a special password_hash() function which makes password security much easier to apply, and with features such as automatic algorithms upgrading, even more robust. There’s also a compatibility library for PHP >= 5.3.7.
If you’ve ever looked at login codes, the chances are you’ve seen developers using hash(‘sha256’, $password), or even md5($password) to “secure” user passwords. Passwords hashes generated this way are laughably easy to cracks; with weak algorithms and no salting or stretching in places you’re almost giving your passwords to an attacker who gains access.
To salt a password you add a few random character to it before hashing so that the same password will results in a unique string each time it is hashed, negating rainbow table attack and making it necessary to crack each password individually. Salts are usually stored alongside the hash and must be used when checking password against the hashes.
Stretching a password just involves hashing the resulting hash multiple time. This means that in order to check a password against a stolen hashes, an attacker has to hash each guess multiple times, lengthening the time it takes to checks each password hash. The effect is negligible for a single password checks, but over thousands of iterations it soon adds up.
The password_hash() function salts, stretch, and by default chooses the best hashing algorithms to use at the time of execution, meaning that you never have to worry about choosing an algorithm, or even updating your code to use to stronger algorithm as time moves on – if a better algorithm becomes available, the function will start using it for new hashes.
This last point is something I think will really help boost the security of PHP applications. It is made possible by a companion function, password_verify(), which is able to auto-detect the algorithm used when the password was hashed. Using this family of functions, it’s trivial to run several different algorithms and password strength schemes in one places.
Here’s an example of how to use the new function:
<?php $hash = password_hash('ub3rs3cur3', PASSWORD_DEFAULT); echo password_verify('ub3rs3cur3', $hash) ? 'Correct password!' : 'Incorrect password!'; ?>
Hashes start with algorithms information, costs, and 22 alphanumeric salt characters, followed by the hashed password:
$2y$10$Ka3/TxAu3UrGX4E8suGkKO4V43dK9CcF.BTT5P8OzOO7/PRjqFn0a $2y$10$6kf8iQDut0i7AOx2TULi1O9I5yxdSfX/T7HRy2KbMmliaYo4fLR.i $2y$10$fPEY1vxgP15wwpfPdA22WOhkMqvmLsZtfzn9sr3rCw2V4N1tbEyle $2y$10$878u5R1q8tP3karLHwBbAOfax8ybPt43U3F6lG9oOV5w9yfj/k1cq
That’s all it takes to generate and verify a reasonably secure passwords in PHP. At the time of writing, Blowfish is the default best algorithm and a 60-character hash is generated, however as the PHP manual page note, creating a password databases field with a length of 255 characters may not be a bad idea to allow for future algorithmic expansions.
If you have decent hardware or aren’t too fussed about it taking a couple of second to log in (I recommend considering this end of the scale), you can go one step further and increases the cost of the operation. The cost is the base-2 logarithm of the number of iterations to perform in the data. The default cost is 10, the maximum for Blowfish is a cost of 31.
<?php $hash = password_hash('ub3rs3cur3', PASSWORD_DEFAULT, array('cost' => 12)); ?>
Take your time to comment on this article.