0

I have read the other posts to this topic but haven't found a solution to this one. Here is my code, reduced to the bare functionality:

<?php

$password = "YS7Wde5s";

$hashA = password_hash($password, PASSWORD_BCRYPT);
echo $hashA . "<br>";

// Copied from echo above
$hashB = "$2y$10$nltCAZhbMD2OILgq2ftWNOd6kJL8oidQ12CLEM5Gi1kIj5GxKtNhm";

if (password_verify($password, $hashA)) {
    echo "yes";
} else {
    echo "no";
}
?>

The above code works well using $hashA to verify the password. BUT:

  • The echo of $hashA returns a different hash whenever I reload the page.
  • If I copy the echoed hash, hardcode it in $hashB, and use this instead of $hashA, I never get a true out of the password_verify call.

What am I missing? Is there an implicit type conversion I don't know about? Or am I completely wrong in how this should work?

William Perron
  • 1,288
  • 13
  • 18
Sir Tobi
  • 142
  • 1
  • 8
  • Yes, thats why you should use this function because it is more secure that one that hashes the same string to the same hash always, like MD5 or SHA1 – RiggsFolly May 02 '18 at 17:45
  • 1
    You get a different each time because Bcrypt appends a random value (commonly refered to as a "salt") to the password. This is done to prevent dictionary attacks on the database and force the attacker to brute-force the hash, which a computationaly expensive procedure. – William Perron May 02 '18 at 17:47
  • @RiggsFolly I guessed that but wasn't sure about that. – Sir Tobi May 02 '18 at 17:48
  • This is the expected behavior. `BCRYPT` adds salt to prevent brute force. Its a good thing ;) – Rotimi May 02 '18 at 17:49
  • you mention that `password_verify()` on `$hashB` never returns `true`, if you are using the same password, it should work, there may be something wrong with the way you are verifying it – William Perron May 02 '18 at 17:50
  • @Sammitch that's already what OP is doing – William Perron May 02 '18 at 17:50
  • Thats why `password_verify()` is provided. It will look at the HASH and use the same salt and Cost count as was used in the original HASH. See those are stored in the HASH and `password_verify()` knows how to get the right bits from the original hash – RiggsFolly May 02 '18 at 17:51
  • 7
    The problem is the double quotes around the `$hashB` value; with double-quoted strings, variable interpolation is attempted (looking for a variable called `$nltCAZhbMD2OILgq2ftWNOd6kJL8oidQ12CLEM5Gi1kIj5GxKtNhm`). If you turn on displaying `E_NOTICE` messages, you'll see *"Notice: Undefined variable: nltCAZhbMD2OILgq2ftWNOd6kJL8oidQ12CLEM5Gi1kIj5GxKtNhm"*. The value of `$hashB` is actually only `"$2y$10"`. – salathe May 02 '18 at 17:51
  • @WilliamPerron What you are saying is that using $hashB using the echoed hash in the above code SHOULD return true. Right? – Sir Tobi May 02 '18 at 17:52
  • @salathe This. The problem has nothing to do with the password APIs; it's a syntax issue. –  May 02 '18 at 17:53
  • @salathe GENIUS! – Sir Tobi May 02 '18 at 17:53
  • @SirTobi if `$hashB` was generated using the same password as `$hashA`, then using `password_verify()` with that password and `$hashB` should work – William Perron May 02 '18 at 17:59
  • @salathe great catch, I wouldn't have thought of that, you should post it as an answer – William Perron May 02 '18 at 18:00

1 Answers1

6

The double quotes around $hashB are causing everything within the hash value following the $, to be interpreted as a variable. (https://secure.php.net/manual/en/language.types.string.php)

Use single quotes instead.

The following note on the php manual explains it better than I:

Funk Forty Niner
  • 74,450
  • 15
  • 68
  • 141