When you have to save user’s password in a database you should never store them in plain text for security precautions and privacy. If we do hashing the passwords before saving them to the database we will have a safety mechanism for not revealing them to the atacker.

One of the most popular but wrong way of hashing password was using md5() function that calculates md5 hash of a string. Hashing passwords with md5 (or sha1 or even sha256) is bad because these hashes can get decrypted.

<?php // plain text password $password = 'secretcode' ; // hash the password with md5 $md5 = md5 ($password);

Common solution to preventing decryption is using the salt.

<?php // plain text password $password = 'secretcode' ; // add random characters - the salt $salt = 'k*jJlrsH:cY]O^Z^/J2)Pz{)qz:+yCa]^+V0S98Zf$sV[ [email protected] {utg%OlODS' // hash salt and password together $md5 = md5 ($salt . $password);

This is still not good enough though - Rainbow tables. Cryptography is a large field and quite complex for lot of people so leave it to the experts.

Right & Secure way of hashing passwords as of PHP 5.5

Right way of hashing passwords is currently using PHP 5.5 and its native passwords hashing API which provides an easy to use wrapper around crypt function.

Example of PHP 5.5 native password hashing API usage:

<?php // plain text password $password = 'secretcode' ; // The cost parameter can change over time as hardware improves $options = [ 'cost' => 12 ]; echo password_hash ($password, PASSWORD_DEFAULT , $options);

In password_hash function there are two types of algorithms available. PASSWORD_DEFAULT and PASSWORD_BCRYPT. Currently PASSWORD_DEFAULT is PASSWORD_BCRYPT. In future there will be different types of algorithms supported and PASSWORD_DEFAULT will get replaced with a new type of algorithm. Good advice is to always use PASSWORD_DEFAULT.

Using your own salt might not be a very good option. Leave that to the experts as well and use above bullet proof solution without setting your own salt. Salt is randomly generated by default in password_hash function.

Another option that is important to mention is the cost which controls the hash speed. On servers with better resources cost can be increased. There is a script for calculating the cost for your environment in the PHP manual.

Verifying passwords can be done with password_verify():

<?php // this is the hash of the password in above example $hash = '$2y$12$3BZAuYlYaaz4hdxuZRsEV.D69wq.oiT18cVhqoxIsmGkd4JbCq8Ai' ; if ( password_verify ( 'secretcode' , $hash)) { echo 'Password is valid!' ; } else { echo 'Invalid password.' ; }

Regenerate hash if algorithm or cost changed

When you change the cost or hashing algorithm, hash needs to regenerated. For this purpose, password_needs_rehash() comes to the rescue, 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. This comes handy in case of server hardware upgrade and therefore increasing the cost option.

<?php // Check if a newer hashing algorithm is available // or the cost has changed if ( password_needs_rehash ($hash, PASSWORD_DEFAULT , $options)) { // If so, create a new hash, and replace the old one $new_hash = password_hash ($password, PASSWORD_DEFAULT , $options); } ?>

Password hashing in PHP versions <5.5

In case you’re not yet using PHP 5.5 or above there is a way to secure passwords in PHP version > 5.3.7 by using for example PHP library password_compat. PHP library password_compat works exactly the same way as does the native PHP’s 5.5 password hashing API so when you upgrade to PHP 5.5 or above you will not need to refactor your code.

Resources:

PHP.net passwords FAQ 2. securepasswords.info - A polyglot repo of examples for using secure passwords