Home  >  Q&A  >  body text

Laravel 9 rejects valid password hashed with bcrypt

I've spent a few days troubleshooting some password validation failures in Laravel 9. Password testperson resolves to hash $2y$10$5xc/wAmNCKV.YhpWOfyNoetCj/r3Fs5TyAskgZuIF/LEItWfm7rPW. A direct query of the corresponding database table confirms that this is the correct hash value. However Laravel's authentication infrastructure rejects this password and refuses authentication.

This is not common. I have multiple passwords that parse correctly. For example, the password eo resolves to $2y$10$uNWYvMVmagIwQ2eXnVKLCOAK1QFQdcRtxbvlghf.Xpg0U1w.N./N2, and Laravel validates the password. The same mechanism creates both user records, although they have different permissions (indicated by a boolean value on the record).

I found a bug in the function password_verify, which was determined to be returning false negatives in this Stack Overflow question and this Treehouse thread.

Specifically, this is the stack in Laravel where this failure point occurs:

After unwinding the entire stack, I run the following code in the login method of the login controller:

$provider = $this->guard()->getProvider();
$credentials =  $this->credentials($request);
$user = $provider->retrieveByCredentials($credentials);
$password_unhashed = $request['password'];
$password_hashed = $user->getAuthPassword();
$password_verify = password_verify($password_unhashed, $password_hashed);
logger('attemping login', compact('password_verify','password_unhashed','password_hashed'));

Dump this context:

{
"password_verify": false,
"password_unhashed": "testperson",
"password_hashed": "yxc/wAmNCKV.YhpWOfyNoetCj/r3Fs5TyAskgZuIF/LEItWfm7rPW"
}

If I put that password into a SELECT users WHERE password= query, I get the users I expect.

How is this going? How can I solve this problem?

P粉270842688P粉270842688178 days ago395

reply all(1)I'll reply

  • P粉464082061

    P粉4640820612024-03-29 11:37:34

    I think your assertion that the hash you provided is the "testperson" hash is actually false. Since hashes are one-way, I can't tell you where the hash shown comes from. NOTE: It works on PHP 7.4, but I don't think it will work on PHP 8 and above since the salt option in passwd_hash() is deprecated.

     10, "salt" => substr($testhash, 7, 22));
    $pwhash = password_hash($password, PASSWORD_BCRYPT, $options);
    echo $pwhash."\n";
    $salt = substr($pwhash, 0, 29);
    echo $salt."\n";
    $cryptpw = crypt($password, $salt);
    echo $cryptpw."\n";
    if (password_verify($password, $cryptpw)) {
      echo("Verified.\n");
    } else  {
      echo("NOT Verified.\n");
    }
    if (password_needs_rehash($cryptpw, PASSWORD_BCRYPT, $options)) {
      echo("Needs rehash.\n");
    } else {
      echo("Doesn't need rehash.\n");
    }
    
    /*
    testperson results...
    yxc/wAmNCKV.YhpWOfyNoeVNPMEcYrxepQeFAssFoAaIYs4WLmgZO
    yxc/wAmNCKV.YhpWOfyNoe
    yxc/wAmNCKV.YhpWOfyNoeVNPMEcYrxepQeFAssFoAaIYs4WLmgZO
    Verified.
    Doesn't need rehash.
    
    eo results...
    y$uNWYvMVmagIwQ2eXnVKLCOAK1QFQdcRtxbvlghf.Xpg0U1w.N./N2
    y$uNWYvMVmagIwQ2eXnVKLCO
    y$uNWYvMVmagIwQ2eXnVKLCOAK1QFQdcRtxbvlghf.Xpg0U1w.N./N2
    Verified.
    Doesn't need rehash.
    */
    ?>

    reply
    0
  • Cancelreply