Because of security matters!

Whenever we develop a user based web application system, we have a common problem of storing the password in the database with correct security standards. In this blog, we will see the feature provided by PHP for the same.

I still remember days when we used  MD5  or SHA1 hashing to store passwords. Many folks are still using them.  One can easily crack the hash generated from MD5 and SHA1 functions using Rainbow Algorithm.

<?php // below example is for just for understanding how md5 is used. $password = '[email protected]'; // output of below function will be 32 digit hexadecimal string 0f359740bd1cda994f8b55330c86d845 echo md5($password); ?>

there are certain sites which have stored hashes of MD5 functions e.g  https://crackstation.net. On this site when you enter MD5 hash it will give you original input from stored mapping. Hence, to overcome this situation we add extra salt with the password, generating a more complex hash.

<?php $password = '[email protected]'; // generate some radom value $salt = md5(microtime()); // output of below function will be 32 digit hexadecimal string.  md5($password . $salt); ?>

using salt mechanism we need to store the salt and hash in the database for authentication to succeed.

Although we can avoid it; thanks to PHP community, after version 5.5, they have introduced several PHP hash functions to specifically generate and store password.

The new password hashing API introduce four simple functions:

  1. password_hash() – hashes the password.
  2. password_verify() – verifies a password against its hash.
  3. password_needs_rehash() – used for password rehashing
  4. password_get_info() – returns the name of the hashing algorithm and various options used while hashing.

Let’s me jump more in detail.

1. password_hash()

Creates a new password hash using a strong one-way hashing algorithm.

string password_hash ( string $password , int $algo [, array $options ] ) 

Here the function has three parameters:

  • PASSWORD_DEFAULT – Use the default bcrypt algorithm.
  • PASSWORD_BCRYPT – Use the algorithmCRYPT_BLOWFISH to create the hash. This will produce a standard crypt() compatible hash using the “$2y$” identifier. The result will always be a 60 character string or on FALSE on failure.
The hash description - generated password breakdown

Here, cost and salt are the supported $options. here salt is random text and  cost is used for adding complexity in algorithm if we don’t provide both options than compiler will randomly select salt  and cost would be default 10

warning: The salt option has been deprecated as of PHP 7.0.0. Now the preferred way is to simply use the salt that is generated by default.

  • PASSWORD_ARGON2I – Use the Argon2 hashing algorithm to create the hash. This option is only available for PHP version 7.2.  According to cryptographic expert Argon is one of the best cryptographic function. This algorithm had won  Password Hashing Competition in July 2015.  

supported $options for PASSWORD_ARGON2I is 

  • memory_cost (integer) – Maximum memory (in kibibytes) that may be used to compute the Argon2 hash. Defaults to PASSWORD_ARGON2_DEFAULT_MEMORY_COST.
  • time_cost (integer) – Maximum amount of time it may take to compute the Argon2 hash. Defaults to PASSWORD_ARGON2_DEFAULT_TIME_COST.
  • threads (integer) – Number of threads to use for computing the Argon2 hash. Defaults to PASSWORD_ARGON2_DEFAULT_THREADS.

2. password_verify()

password_verify() a function will be used to verify hash or password generated using a password_hash function

bool password_verify ( string $password , string $hash )

Thepassword_verify()function takes a plain password and the hashed string as its second arguments. It returns true if the hash matches the specified password. 

<?php if (password_verify($password, $hash)) {     // Success! if given password and hash match other wise it will return false. } else {     // Invalid credentials }

This function is safe enough for timing attack.

3. password_needs_rehash()

This function checks to see if the supplied hash implements the algorithm and options provided. If not, it is assumed that the hash needs to be rehashed

bool password_needs_rehash ( string $hash , int $algo [, array $options ] )
  • $hash is a hash which password_hash() function had generated in the first place.
  • $algo is denoting the algorithm used in password_hash(). e.g ( PASSWORD_BCRYPT or PASSWORD_ARGON2I)
  • Supported options according to the requirement of $algo go in $options.

We use this function when we change application wise $algo or its relevant $options.

<?php

$new = [
    'options' => ['cost' => 11],
    'algo' => PASSWORD_DEFAULT,
    'hash' => null
];

$password = 'rasmuslerdorf';

//generated hash of password
$oldHash = '$2y$07$BCryptRequires22Chrcte/VlQH0piJtjXl.0t1XkA8pw9dMXTpOq';

//first we verify stored hash against plain-text password
if (true === password_verify($password, $oldHash)) {
    // verify legacy password to new password_hash options
    if (true === password_needs_rehash($oldHash, $new['algo'], $new['options'])) {
        // rehash/store plain-text password using new hash
        $newHash = password_hash($password, $new['algo'], $new['options']);
        echo $newHash;
    }
}
?>

The above example will output something similar to:
$2y$11$Wu5rN3u38.g/XWdUeA6Wj.PD.F0fLXXmZrMNFyzzg2UxkVmxlk41W

4. password_get_info()

Above function will give us information about given hash.

// here $hash should be valid hash generated using password_hash function
array password_get_info ( string $hash )
on valid input above function give us an associative array of the algorithm, algoName and constant.
 
 
So new password hash API in PHP is really good for storing and easy for storing passwords.
 
Project Password hashing
CMS Airship Argon2i
Drupal SHA512Crypt with multiple rounds
Joomla bcrypt
Laravel bcrypt with other options
Symfony bcrypt with other options
WordPress salted MD5
References: