PHP Password Hashing API Tutorial

Learn how to use PHP 5.5’s password hashing API to store your user passwords more securely. A simple to use API that helps developers move towards bcrypt.

Are you hashing your user passwords? If not, you’re asking for trouble (just look at the recent password leaks). Keeping plain text passwords or using older, weaker algorithms like MD5 or SHA1 to store passwords have become outdated and less secure than newer, modern methods. For instance, with the release of PHP 5.5, you can use the new password hashing api.

Everybody knows that you should be hashing user passwords using bcrypt, but still a surprising number of developers uses insecure md5 or sha1 hashes. One of the reasons for this is that the crypt() API is ridiculously hard to use and very prone to programming mistakes.

PHP Password Hashing Functions

By adding a new, very simple to use API PHP hopes to move more developers towards bcrypt. It has four simple functions:

  • password_hash() – used to hash the password
  • password_verify() – used to verify a password against its hash
  • password_needs_rehash() – used when a password needs to be rehashed
  • password_get_info() – returns the name of the hashing algorithm and various options used while hashing

How to Hash Passwords Using PHP

Although the crypt() function is secure, it’s considered by many to be too complicated and prone to programmer error. Some developers then use a weak salt and weak algorithm for generating a hash instead, for example:

[code_highlight lang=”php”]$hash = md5($password . $salt); // works, but dangerous[/code_highlight]

But the password_hash() function can simplify our lives and our code can be secure. When you need to hash a password, just feed it to the function and it will return the hash which you can store in your database. Creating password hashes can’t be any simpler than this:

[code_highlight lang=”php”]$hash = password_hash( $password, PASSWORD_DEFAULT );[/code_highlight]

This will create a password hash using the default algorithm (currently bcrypt), the default load factor (currently 10) and an automatically generated salt. The used algorithm and salt will also be part of the resulting hash, so you don’t need to worry about them at all.

If you don’t want to stick with the defaults (which might change in the future), you can also provide algorithm and load factor yourself:

[code_highlight lang=”php”]$hash = password_hash( $password, PASSWORD_BCRYPT, [‘ cost’ => 12 ] );[/code_highlight]

That’s it! The first parameter is the password string that needs to be hashed and the second parameter specifies the algorithm that should be used for generating the hash.

The default algorithm is currently bcrypt, but a stronger algorithm may be added as the default later at some point in the future and may generate a larger string. If you are using PASSWORD_DEFAULT in your projects, be sure to store the hash in a column that’s capacity is beyond 60 characters. Setting the column size to 255 might be a good choice. You could also use PASSWORD_BCRYPT as the second parameter. In this case the result will always be 60 characters long.

The important thing here is that you don’t have to provide a salt value or a cost parameter. The new API will take care of all of that for you. And the salt is part of the hash, so you don’t have to store it separately. If you want to provide your own salt (or cost), you can do so by passing a third argument to the function, an array of options.

[code_highlight lang=”php”]$options = [
‘salt’ => custom_function_for_salt(), //write your own code to generate a suitable salt
‘cost’ => 12 // the default cost is 10
];
$hash = password_hash($password, PASSWORD_DEFAULT, $options);[/code_highlight]

In this way, you are always up-to-date with new security measures. If PHP later decides to implement a more powerful hashing algorithm your code can take advantage of it.

Verifying PHP Hashed Passwords

Now that you have seen how to generate hashes with the new API, let’s see how to verify a password. Remember that you store the hashes in a database, but it’s the plain password that you get when a user logs in.

The password_verify() function takes a plain password and the hashed string as its two arguments. It returns true if the hash matches the specified password. Verifying passwords is just as easy:

[code_highlight lang=”php”]// $password from user, $hash from database
if (password_verify($password, $hash)) {
// password valid!
} else {
// wrong password 🙁
}[/code_highlight]

Just remember that the salt is a part of the hashed password which is why we are not specifying it separately here.

Rehashing PHP Passwords

As time goes by you might want to change the password hashing algorithm or load factor, or PHP may change the defaults to be more secure. In this case new accounts should be created using the new options and existing passwords rehashed on login (you can do this only on login because you need the original password to do a rehash).

Doing this is also very simple:

[code_highlight lang=”php”]function password_verify_with_rehash( $password, $hash ) {
if ( ! password_verify( $password, $hash ) ) {
return false;
}

if ( password_needs_rehash( $hash, PASSWORD_DEFAULT ) ) {
$hash = password_hash( $password, PASSWORD_DEFAULT );

// update hash in database
}

return true;
}[/code_highlight]

The above snippet will keep your hashes up to date with the PHP default. But once again you can also specify custom options, e.g. password_needs_rehash($hash, PASSWORD_BCRYPT, ['cost' => 12']).

Retrieve PHP Hashed Password Info

Use password_get_info() to return an associative array with information about the given hash. When passed in a valid hash created by an algorithm supported by password_hash(), this function will return the following:

  • algo – a constant that identifies a particular algorithm
  • algoName – the name of the algorithm used
  • options – various options used while generating the hash

Compatibility for Older PHP Versions

The new API will only be introduced in PHP 5.5. Those who are using PHP 5.3.7 (or later) can use a library called password_compat which emulates the API and automatically disables itself once the PHP version is upgraded to 5.5.


Conclusion

The PHP password hashing API is definitely easier to work with than fumbling with the crypt() function. If your website is currently running on PHP 5.5, then I strongly recommended that you use the new hashing API. Learn more about the PHP password hashing API:

Author: Ben Marshall

Red Bull Addict, Self-Proclaimed Grill Master, Entrepreneur, Workaholic, Front End Engineer, SEO/SM Strategist, Web Developer, Blogger

Leave a Reply

Your email address will not be published. Required fields are marked *