I am working on an existing Symfony
2.8 web app project that uses FOSUserBundle
for user authentication.
In addition to the web front end the users can use different smartphone client to connect to the web app using a REST API. Thus the users need to be authenticated both when logging in directly in the web app and when connecting why the REST API.
Until one of the latest FOSUserBundle
updates a bcrypt
password hash and the used salt
where stored in the database.
When connecting using the REST API, the salt is transferred to the client to locally hash the password using the same salt. The hashed password is than send back to the web app for authentication.
I know that sending the hashed password instead of plain text does not add (a lot of) additional security, since the communication is only possible using HTTPS. However this is the way the clients work: They need the salt to generate the hashed password. I can update the clients in the future, but right now this is just the way the work.
The Problem:
They way FOSUserBundle
hashes the password has changed: Since it is considered to be saver to NOT specify the salt manually but to let PHP generate the salt automatically (in PHP 7 it is not even possible to manually set the salt), a manual salt is no longer supported.
This is no problem when logging into the web app directly, but since the REST clients still need a salt, this updates breaks the REST connection.
Is there any way to combine both methods? Let PHP create the salt automatically, extract and send this salt to the clients?
As far as I understand the salt is stored with the hash in the same string:
However, simply copy the 21 char salt from the hash-string and send these to the clients does not work. It seems that these 21 chars a enough to test/verify the password, but not to re-create the hash. Is this correct?
So, is there any solution to use PHP password_hash
without setting a salt, and to get to know the used salt at the same time?
EDIT 1:
To answer @RiggsFolly question: MD5 was not used at any time. It is not correct, that bcryp
/password_hash
will not create the same hash twice. It will do so, if both the password and the salt are the same:
$s = 'password';
$salt = 'salt5678901234567890123456789012';
$options['salt'] = $salt;
$h1 = password_hash($s,PASSWORD_BCRYPT,$options);
$h2 = password_hash($s,PASSWORD_BCRYPT,$options);
echo $h1 . PHP_EOL;
echo $h2 . PHP_EOL;
Result:
$2y$10$salt56789012345678901uTWNlUnhu5K/xBrtKYTo7oDy8zMr/csu
$2y$10$salt56789012345678901uTWNlUnhu5K/xBrtKYTo7oDy8zMr/csu
password_hash
will create a new hash for the same password, if the salt is not specified. This is because, the salt will be created randomly which is than of cause different on each call.
EDIT 2:
As one can see in Edit 1, using a salt with 32 chars will result in a string that only includes the first 21 chars of the salt. However this salt-prefix cannot be used to re-create the same hash since it is too short to be accepted.
However, if the prefix is filled up with 0, it seems to work:
$s = 'password';
$salt = 'salt5678901234567890123456789012';
$salt_prefix = 'salt5678901234567890100000000000';
$h1 = password_hash($s, PASSWORD_BCRYPT, array('salt' => $salt));
$h2 = password_hash($s, PASSWORD_BCRYPT, array('salt' => $salt_prefix));
echo $h1 . PHP_EOL;
echo $h2 . PHP_EOL;
So a solution could be:
FOSUserBundle
use password_hash
to create the hash without manually specifying a salt.Can anyone confirm, that this a real solution and not just some coincidence ?
You seem to misunderstand how password hashing and salts are supposed to work.
The salt is never sent to the client. It is generated (or manually specified) only once when the password is created. Its purpose is to randomize the output of the hash function, so that when the database gets into the wrong hands it is not possible to get users passwords by comparing the output to rainbow tables.
When the user uses his password to login the password is sent from the client to the server unhashed (but usually over https). The password comparing function then fetches the stored hash+password, gets the salt from it, appends the salt to the user input, calculates the hash and then compares that to the hash from the database.
Maybe the project you're on has a bad implementation of salts. In fact, one of the reasons using manual salts is discouraged is to prevent things like this.
So a solution could be:
let FOSUserBundle use password_hash to create the hash without manually specifying a salt.
extract the salt from the result string and pad it with 0 to a length of 32 chars
pass this salt to the client
Can anyone confirm, that this a real solution and not just some coincidence ?
This is not a good solution. The only good way is to make sure password hashing is implemented the right way so you don't have to generate the salt more than once.