Search code examples
phpmysqlipassword-hash

password_verify not matching after writing to database


I think my problem is environmental, but I have tapped everything I can think of to find it. The code was working fine 3 weeks ago, and suddenly stopped a few days ago. I haven't updated the O/S or PHP in that timeframe.

I'm using password_hash to create a password from a $_POST variable, and then writing it to a MySQL database field (set to varchar(255)). After the problem came up I added test code to do password_verify on the variable in memory before writing to the database, and then re-read the value from the database after writing it there. In both cases it returns as a match. However, any other page trying to run password_verify returns as a mismatch. I have captured the initial hash and visually compared it to the value in the database and they are identical. Both servers (the one that generates the hash and the one that reads it when the user logs in are both running the same version of php (5.6.9-0+deb8u1).

Here's my complete code in it's current state of debugging. In the code below the commented out line using PASSWORD_DEFAULT is what I was originally using. I tried BCRYPT option just to see if it would fix it. I also tried putting $_POST['password'] into a variable instead of calling it directly, and wrapping a trim around it. Everything seems fine until I leave this page and try from another page. I have also checked the items discussed in other posts on the web.

//USER DOES NOT EXIST 
mysqli_close($con);
if (mysqli_connect_errno())
{
    echo "Failed to connect to MySQL: " . mysqli_connect_error();
    $error = true;
}
// New user - add them to database
echo "Creating your account. <br>";
$pwd = $_POST['password'];
//$password = password_hash(trim($_POST['password']), PASSWORD_DEFAULT);    
$password = password_hash($pwd, PASSWORD_BCRYPT);   
echo $password . '<br>';


$sel = 'CALL sp_add_user("'. $_POST['firstname'] . '","'. $_POST['lastname'] . '","'. $_POST['email1'] . 
    '","'. $_POST['city'] . '","'. $_POST['country'] . '","'. $password . '","'. $timestamp . '")';

$con=mysqli_connect($conip,$dbuser,$dbpw,$mgrdb);
if(!mysqli_query($con, $sel))
{
    echo("Error description: " . mysqli_error($con));
}
else{
    mysqli_close($con);
    //verify the password in the DB is good
    $sel='CALL sp_get_pwd("' . $_POST['email1'] . '")';
    //echo $sel;
    $con=mysqli_connect($conip,$dbuser,$dbpw,$mgrdb);
    $result = mysqli_query($con, $sel);
    if (mysqli_num_rows($result)>0){
        while($row = mysqli_fetch_array($result)) {
            $dbpwd = $row['password'];
        }
    }
    echo $dbpwd . '<br>';
    if(password_verify(trim($_POST['password']), $dbpwd)){echo 'Match<br>'; } else { echo 'Match failed<br> ';} 
    mysqli_close($con);

Solution

  • I simulated your code without database and form fetching, and it runs ok. It means there's something wrong either with your database or with your POST fields.

    // New user - add them to database
    echo "Creating your account. <br>";
    $pwd = '12345';
    //$password = password_hash(trim($_POST['password']), PASSWORD_DEFAULT);    
    $password = password_hash($pwd, PASSWORD_BCRYPT);   
    echo $password . '<br>';
    
    $dbpwd = $password;
    
    echo $dbpwd . '<br>';
    if(password_verify(trim($pwd), $dbpwd))
    {
        echo 'Match<br>';
    }
    else
    {
        echo 'Match failed<br> ';
    }
    

    Output:

    Creating your account.
    $2y$10$iw6fSApO7Ok0ySZ.OsQqbe.DpVrvzJ86ZYIsWYg5060hyXbBYEiee
    $2y$10$iw6fSApO7Ok0ySZ.OsQqbe.DpVrvzJ86ZYIsWYg5060hyXbBYEiee
    Match
    

    Use var_dump on your hashed $password var before the INSERT, then again with your $dbpwd after the SELECT and see if you get anything wrong. Also, check your PHP project scripts and your database schema for conflicting charset definitions.