php password_verify not working with database
Solution 1
Found the problem. when I did this:
echo strlen($hash)
it printed 90, which is strange because there were definitely no spaces at the end when I printed out the success/failure message, and the field has a varchar length of 255
I added this line:
$hash = substr( $hash, 0, 60 );
And now it works fine.
Its strange that no one else seems to have run into this issue. There are similar posts about password_verify, but none of them required this type of conversion, or any conversion for that matter:
php password_verify not working
http://forums.phpfreaks.com/topic/283407-need-help-with-password-verify/
Using PHP 5.5's password_hash and password_verify function
One thing that bothers me is this prevents the code from being forward compatible. How will I know that the hash is 60 characters long when the default changes?
Solution 2
I was having the same issue with password_verify(). For me i had declared my username and password as VARCHAR(50). Therefore it was not inserting the hash value in my database which is obviously more than 50 characters. Therefore every time I used password_verify() I got a false. I changed my database values to varchar(255). Inserted data again, tested and it works.
Solution 3
Just for future reference. I had the same issue with passwords failing for no reason. When I took a closer look at it I saw that the password field in the database was not big enough to store the full hash so some characters were cut off. After increasing the size of the database field it worked perfectly.
Solution 4
I had the same issue you had with it not working, for some reason it seems to help putting the:
$hash = substr( $hash, 0, 60 );
into the code although my string was already 60 characters long.
Solution 5
I had the same issue and it was still not working despite ensuring my database columns were varchar(255), that the hashes were 60 characters, and ensuring my encoding was UTF-8 all the way through. I'm pretty new to PHP and SQL so I won't pretend to understand exactly why it worked, but I managed to fix it so I hope this post will help other folks with the same problem.
It turned out that the underlying reason password_verify() wasn't verifying my hashes was because I had made a prepared statement that used a stored procedure earlier in the script without fetching all the results from the query properly to clear the buffer, before closing and reopening the connection to perform the next query. Calling next_result() on the mysqli_link after closing the statement will make sure any results are consumed.
Additionally, I was then using another prepared statement with a stored procedure to make the insert for the password, but I still needed to make calls to store_result() and free_result() even though no result sets were returned from the insert. I'm assuming the combination of these things was corrupting my data somewhere along the line, resulting in password_verify() returning false on seemingly identical hashes.
This answer was for a different problem but I found it useful for learning how to properly close out prepared statements with stored procedures.
Related videos on Youtube
Cbas
Updated on July 09, 2022Comments
-
Cbas almost 2 years
I am using php 5.4 with this backwards compatibility script: https://github.com/ircmaxell/password_compat/blob/master/lib/password.php
that shouldn't matter though, because I can get the hashing and verification process working in my registration function:
$hash = password_hash($pass, PASSWORD_DEFAULT); echo $pass; echo $hash; if( password_verify($pass,$hash) ) echo 'success'; else echo 'failure'; //success is always shown //EXAMPLE INPUT $pass = 'password'; //EXAMPLE OUTPUT password$2y$10$JK1jumvvSIm/gP3fWE3k9O98MzvHKDRYCjRPBniYg9riACyQw7WYSsuccess
but whenever I try to store the hash in a MySQL database and then retrieve it for the verify function, it always fails. Here is my login function:
function user_login( $mysqli, $email, $pass ){ $err_msg = 'login: '.$mysqli->error.' | '.$email; if( $stmt = $mysqli->prepare('SELECT password FROM users WHERE email=?') ) : if( !$stmt->bind_param('s', $email) ) log_sql_error( $err_msg ); if( !$stmt->execute() ) log_sql_error( $err_msg ); if( !$stmt->bind_result( $hash ) ) log_sql_error( $err_msg ); if( $stmt->fetch() === FALSE ) log_sql_error( $err_msg ); if( !$stmt->close() ) log_sql_error( $err_msg ); //I can see that these values are identical to the ones //echoed out in the registration function echo $pass; echo $hash; if( password_verify($pass,$hash) ) echo 'success'; else echo 'failure'; else : log_sql_error( $err_msg ); endif; } //failure is always shown //EXAMPLE INPUT $pass = 'password'; //EXAMPLE OUTPUT password$2y$10$JK1jumvvSIm/gP3fWE3k9O98MzvHKDRYCjRPBniYg9riACyQw7WYSfailure
My 'password' column has this datatype:
VARCHAR(255) NOT NULL
No php errors show up so the only thing I can think of is that the hash value is not formatted in the same way when it comes out of the database as when it went in, but when I echo out the values, they appear to be identical.
How else can I debug this / what is wrong with my code?
Thanks
UPDATE:
This definitely has something to do with encoding:
$hardcode_hash = '$2y$10$JK1jumvvSIm/gP3fWE3k9O98MzvHKDRYCjRPBniYg9riACyQw7WYS'; echo $hash; echo '<br/>'; echo $hardcode_hash; echo '<br/>'; if( $hash == $hardcode_hash ) echo 'success'; else echo 'failure'; //OUTPUT $2y$10$JK1jumvvSIm/gP3fWE3k9O98MzvHKDRYCjRPBniYg9riACyQw7WYS $2y$10$JK1jumvvSIm/gP3fWE3k9O98MzvHKDRYCjRPBniYg9riACyQw7WYS failure
how do I reformat the SQL value to match the output of password_hash? Here's what I've tried:
(string)$hash utf8_encode($hash)
if I do:
$hash = settype($hash,"string");
if($hash == $hardcode_hash)
returns true, butpassword_verify($pass, $hash)
still returns false-
mario over 9 yearsYou could showcase the sample
$pass
and$hash
output. Noone is able to testrun your code excerpt. -
Cbas over 9 yearsadded example outputs - as you can see, the strings are identical, but the second password_verify fails
-
mario over 9 yearsUse
var_dump
. If the strings were really identical, it couldn't possibly fail in the second case. -
martinstoeckli over 9 yearsDid you check the encoding of your pages/db, is it possible that one variable contains a multibyte string, while the other doesn't?
-
Cbas over 9 yearsI think you're right about the encoding being different, but I don't know what pages/db is or how to figure out which encoding my database is in - I've been trying various string conversions with no success so far
-
-
martinstoeckli over 9 yearsThis should really not be necessary. Are you sure it is a varchar field and not char*? Maybe you could also have a look at this small article about using UTF-8 for Php (encoding) and database (charset). The code which is inserting the hash into the database could be interesting too.
-
Ashesh about 9 yearsadding to inputs of @martinstoeckli, it would be better to use
CHAR
data type for the hashed password field in the database and set 60 as its length on usingPASSWORD_BCRYPT
constant. In this case the hash will always be 60 characters long. -
Timothy Steele about 8 yearsYour links to other solutions led me to the answer. Thanks! Specifically it was "password_verify not working" that lead me to my solution.
-
Don Beto about 8 years@Cbas I had the same issue. I tried trim($hash) instead of substr() and it works!
-
HADI over 2 yearsI had the same issue. Glad you commented! Thank you.