Introduction to hashing passwords in PHP (5.5+)

Every PHP developer at some point has a need for restricting access to certain parts of their web application and allow users to pass through secure areas with a username and password.

Due to it’s long history, PHP has a lot of practices around security which are no longer secure, or appropriate for the application requirements these days. Among such practices is hashing and securing passwords using algorithms such as MD5, SHA1, etc.

Securing passwords with md5, SHA1, SHA256 or custom hash generators is considered bad practice these days. According to PHP.net

Hashing algorithms such as MD5, SHA1 and SHA256 are designed to be very fast and efficient. With modern techniques and computer equipment, it has become trivial to “brute force” the output of these algorithms, in order to determine the original input.

Because of how quickly a modern computer can “reverse” these hashing algorithms, many security professionals strongly suggest against their use for password hashing.

The methods considered secure a few years ago, are now obsolete/insecure due to ever increasing computing power and advanced techniques. And unless you are well versed in the area of cryptography and security, it is never a good idea to roll your own security mechanisms.

The current best practice is to use the native password hashing API, introduced in PHP version 5.5. The API provides two useful functions, namely password_hash and password_verify.

password_hash() creates a new password hash using a strong one-way hashing algorithm.

password_verify() verifies that the given hash matches the given password.

Using these functions is fairly straightforward. See the following example.

<?php

$hash = password_hash('valid_password', PASSWORD_DEFAULT);

if (password_verify('invalid_password', $hash)) {
    // Correct Password
} else {
    // Wrong password
}

password_hash() currently provides Blowfish algorithm for creating the hash, and it is set as the default algorithm. The PASSWORD_DEFAULT constant is currently set to use the Blowfish algorithm. However, you may specify the Blowfish algorithm explicitly using the PASSWORD_BCRYPT constant, if the requirement is to always use Blowfish. Note that the password_verify() function is forward compatible, therefore PASSWORD_DEFAULT is the preferred option as it will provide the best possible hashing mechanism as PHP updates in future, while still working with previously generated hashes.

Blowfish allows specifying the cost of generating the hash. The cost of the hash implies the complexity and the processing power required to generate the hash. The higher the cost, the more complex the hash, the more processing power and time required to generate the hash. Depending on the use case of the application, and the required security complexity, the cost can be specified. The default cost of the Blowfish algorithm used in password_hash function is 10.

The generated hash is made up of algorithm, cost and salt as part of the returned hash. This eliminates the need to separately generate and store random salt values, and according to PHP.net it is considered simplest and most secure approach.

See the following pages to get up to speed with native Password Hashing API in PHP

UPDATE:

  1. I have corrected the article to reflect the point made by /u/LawnGnome on reddit about hashes being forward compatible, this it is preferred to use PASSWORD_DEFAULT for algorithm.
  2. password_compat library provides the password_* functions for PHP >= 5.3.7. https://github.com/ircmaxell/password_compat – Thanks /u/PolarZoe
  3. Updated Blowfish constant to PASSWORD_BCRYPT, in line with native hashing API.

4 thoughts on “Introduction to hashing passwords in PHP (5.5+)”

  1. In the code example you have a mismatching password leading down the “correct” branch.

    That’s going to lead to one having a very bad time…

    1. The mismatching password will flow down into the else statement. password_verify() will return false due to mismatching password. The example intentionally uses the mismatching password.

Leave a Reply

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

Exit mobile version