Home > Net >  Why is PHP's hashing Algo not working right?
Why is PHP's hashing Algo not working right?

Time:12-31

I use PHP's PASSWORD_DEFAULT as the hashing Algorithm, now i recognized that if i use it with a salt, only the first 8 chars are verified.

Here is a bit of Code i wrote to test that:

<?php 
    $test_pw = "%ImAVery1234Secure!Password$";
    $test_pw_to_be_hashed = "%ImAVery";

    //

    $salt = bin2hex(openssl_random_pseudo_bytes(32));
    $password = $salt.$test_pw;
    $password_hashed = password_hash($salt.$test_pw_to_be_hashed, PASSWORD_DEFAULT);
    echo password_verify($password, $password_hashed);
?>

This returns 1 for me. If i remove one more char from the test_pw_to_be_hashed-value, it returns 0.


Is there any way to hash the whole password? Do i have to use another hashing Algo?

If i have to use another hashing Algo, is there any way to check it with PHP's password_verify-method or do i have to "re-hash" it and then just check both values like this:

if(password_hash($salt.$test_pw_to_be_hashed, OTHER_ALGO) == $db_password)

If i have to change the hashing Algo, is there any way to re-hash the passwords used currently, or do i have to hash them again when i have the plaintext-password (when a user logs in again).

CodePudding user response:

The built-in function password_hash already generates a random hash for you. It returns a string containing the algorithm identifier, the salt and the cryptographic hash. This complete string is confusingly called "hash" itself in the PHP docs. In fact it is a composition containing the hash.

The function password_verify can identify the hash algorithm, the salt and the hash from the string generated by password_hash.

$hash_from_db = '$2y$10$1Ow3T9597X1e9W8dtVbKK.VAAo6Op6xIbglp.3amRCSVgLlTevhjS';
$test_pw      = '%ImAVery1234Secure!Password$';

// this gives another hash each time due to a random salt
echo password_hash($test_pw, PASSWORD_DEFAULT), PHP_EOL;

// this verifies against a strored hash
echo password_verify($test_pw, $hash_from_db) ? 'correct' : 'incorrect';

A cryptographic oneway hash function is meant to be irreversible by design. Thus there is no way to rehash older hashes directly. You have to wait until the next login. Then you can check whether the hash in the database is compliant to the current security standard. Older algorithms will still work. First check as usual, whether the provided password is correct. Then recreate a new hash from the given plain password.

If you for some reason do want an additional own long salt string, you have to store that along with the hash as well. When verifying, you need to use that same salt with the user provided password in the same way as you have built the hash input before and pass the combined string to the password argument of the password_verify function.

Since some crypto algorithm might limit the length of the password input, it is a good idea to append further salt strings to the end of the password rather than prepending. Otherwise in the worst case the verification would always be true when the input is truncated to a shorter length than the length of a prepended salt.

As stated in the password_hash PHP docs

Caution Using the PASSWORD_BCRYPT as the algorithm, will result in the password parameter being truncated to a maximum length of 72 bytes.

bcrypt is the current default algorithm used by password_hash. Thus prepending instead of appending a longer salt would counteract the security.

Though building a longer hash from the generated hash by an own implementation would be possible, cryptography is a complex sciency and custom implementations will most likely introduce more security holes (e.g. timing attacks) rather than increasing security. Use the options provided by PHP's implementations instead, e.g. adjust the cost of the calculation as documented in Predefined Constants. A calculation time of about 3-6 seconds is a fair compromise. This is usually done only once per session and the session is secured by a less secure session id. Consider to reask the password when accessing sensitive data like password change, critical personal information aso.

Keep in mind that even a strong password hash algorithm is considered as not secure enough. Consider to implement multi factor authentication, e.g. sending a TAN to a mail address or mobile phone or even better supporting a cryptographic hardware dongle. (This does not replace but extend password security!)

  • Related