Php – Best way to hash passwords in PHP

hashingpasswordsPHP

I've switched to PHP 7.0 very recently and I was wondering that if password_hash was better than making your own salt and using the crypt function. I have three examples of code and I don't know which make the passwords the most secure.

Example #1 (BCRYPT):

$options = [

    'cost' => 12,

];

$hashed_password = password_hash("foo", PASSWORD_BCRYPT, $options);

Example #2 (PASSWORD_DEFAULT):

$options = [

    'cost' => 12,

];

$hashed_password = password_hash("foo", PASSWORD_DEFAULT, $options);

Example #3 (CRYPT FUNCTION):

$Blowfish_Pre = '$2y$05$';
$Blowfish_End = '$';

$Allowed_Chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789./';

$Chars_Len = 63;

$Salt_Length = 21;

for( $i = 0; $i < $Salt_Length; $i++ )
{
$salt .= $Allowed_Chars[mt_rand(0,$Chars_Len)];
}

$bcrypt_salt = $Blowfish_Pre.$salt.$Blowfish_End;

$hashed_password = crypt($password, $bcrypt_salt);

Best Answer

In your crypt alternative, you construct the salt using mt_rand. This is not recommended, because the cryptographic quality (i;e. it is not random enough) is not sufficient. This is explicitly documented:

CAUTION: This function does not generate cryptographically secure values, and should not be used for cryptographic purposes. If you need a cryptographically secure value, consider using random_int(), random_bytes(), or openssl_random_pseudo_bytes() instead.


The second alternative seems the most promising. The implementation will take care of the secure salting, as underlined in the manual:

Warning: The salt option has been deprecated as of PHP 7.0.0. It is now preferred to simply use the salt that is generated by default.

and:

Caution: It is strongly recommended that you do not generate your own salt for this function. It will create a secure salt automatically for you if you do not specify one.

This means also that if soem weakness is identified in this function, you'll get an improved one, whereas for your custom crypt call, you'd maybe never find out if there would be a flaw.


The first alternative is nice for compatibility. But compared to the second one, it truncates user password at 72 chars. Ok: I admit not to use such a long password, but in some environments, users are instructed to use long passphrases. the default parameter doesn't have this constraint and is hence stronger.

Note also that the length of the hash is 60 bytes in this situation. The default algorithm doesn't specify the exact length but can be longer and may in the long run use stronger longer hashes.