My websites's user login function suddenly stopped working on a rented server( web hosting service) ( It worked wonderfully before for YEARS.) Because I didn't changed anything, the database is also untouched (not hacked or altered), i thought maybe something happened with the PHP settings or modules on the server (because it's a rented server I cannot reach the config files) The server's helpdesk team told me they did nothing / didn't upgrade. ( they don't want to help me solve this. )
As far as I could research the crypt() function "stopped working" (gives back *0 instead of the correct hash as before).
I tried to google for information about how to check the server side settings about or state of crypting / BLOWFISH, but I couldn't find anything, so any help is greatly appreciated!
The salt that worked million times before is look like this:
$salt= '$2a$05$2m6Jboi4zN5V2F/bvUCpH$' ;
$hashed_password = crypt($login_password,$salt);
It doesn't work with my admin login either ( the login credentials are 100% correct )
The users and admin cannot login, the systems tells them the credentials are wrong, which is caused by the checking /matching of a non-existing hash (*0) produced by the crypt() function. ( $password_hash_from_database !== $hashed_password_provided_by_crypt )
Server PHP version is 7.3
Thank you in advance
I'm not very sure, but it's probably because of this security patch: BCrypt hashes erroneously validate if the salt is cut short by `$. Although the version it mentions does not involve PHP 7, due to this being a security vulnerability and easy to fix, it is estimated that your server administrator has applied this patch to your PHP.
Here's a workaround, use $2a$05$2m6Jboi4zN5V2F/bvUCp..
instead of your salt. You will obtain the same encryption result, then to replace the salt part in the result with then to compare the hashed results except for the first 29 characters.$2a$05$2m6Jboi4zN5V2F/bvUCpH.
.
$salt2 = '$2a$05$2m6Jboi4zN5V2F/bvUCp..';
$hashed_password = crypt($login_password, $salt2);
if(substr($hashed_password, 29) === substr($hashed_password_indb, 29))
...
Explanation to the workaround.
The last $
in your old salt $2a$05$2m6Jboi4zN5V2F/bvUCpH$
is not a valid character, according the manual, the valid characters are ./0-9A-Za-z
.
The blowfish algorithm in PHP will convert the last 22 characters of the salt into 4 ints in groups of 4 characters (check the source code)
Because of the vulnerability, the last $
and the preceding H
are actually discarded, and these two bytes will be treated as 0 in actual calculations (.
is the first valid character, so it will be treated as 0). If $
is in another position, there are more digits to be discarded. You can check the following example for comparison:
$login_password = '123345345SDFHSD3453';
$salt1 = '$2a$05$2m6Jboi4zN5V2F/$vUCpH8';
$salt2 = '$2a$05$2m6Jboi4zN5V2F........';
$hashed_password1 = crypt($login_password, $salt1);
$hashed_password2 = crypt($login_password, $salt2);
# $hashed_password1 & $hashed_password2:
# $2a$05$2m6Jboi4zN5V2F/$vUCpHu4CWNoXuc3r8QkJHciPMdM3J.4y2lS.S
# $2a$05$2m6Jboi4zN5V2F........4CWNoXuc3r8QkJHciPMdM3J.4y2lS.S
The first 29 characters are the salt, so it's not necessary to take care of them.