Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<blockquote> <p>Seems 1 big catch point for making strong user password hashes is using random salts as opposed to static ones.</p> </blockquote> <p>Random salts are the default behavior of both PHP 5.5's <a href="https://www.php.net/manual/en/function.password-hash.php" rel="noreferrer"><code>password_hash()</code></a> and the userland implementation, <a href="https://github.com/ircmaxell/password_compat" rel="noreferrer">password_compat</a>.</p> <blockquote> <p>If im checking a user logging in, surely I have to somehow have a copy of the salt used (stored in db) to check?</p> </blockquote> <p>The salt is included in the password hash itself. There is no need to store it separately.</p> <blockquote> <p>The random salt changes each time, so if i stored it now, and the user re-logged in the hash would be different so the db password wouldnt match the posted one..??</p> </blockquote> <p>That's the responsibility of the <a href="https://www.php.net/manual/en/function.password-verify.php" rel="noreferrer"><code>password_verify()</code></a> method. From the PHP docs:</p> <blockquote> <p>Note that password_hash() returns the algorithm, cost and salt as part of the returned hash. Therefore, all information that's needed to verify the hash is included in it. This allows the verify function to verify the hash without needing separate storage for the salt or algorithm information.</p> </blockquote> <p><strong>EDIT: Password Verification and Random Salts</strong></p> <p>I think I understand where your confusion is coming from. Hopefully this will help explain password hashing, verification, and the part played by random salts.</p> <p>If you look at the source of password_compat (<a href="https://github.com/ircmaxell/password_compat/blob/master/lib/password.php" rel="noreferrer">https://github.com/ircmaxell/password_compat/blob/master/lib/password.php</a>), you'll see that both <code>password_hash()</code> and <code>password_verify()</code> make use of PHP's <a href="https://php.net/crypt" rel="noreferrer"><code>crypt()</code></a> function. When you create a password with <code>password_hash()</code>, you store it and never pass that password through <code>password_hash()</code> again. The algorithm, cost, and salt are all returned with the hash. Example:</p> <pre><code>$options = array('salt' =&gt; 'ThisIsTheSaltIProvide.'); $hash = password_hash('password', PASSWORD_DEFAULT, $options); // $hash = $2y$10$ThisIsTheSaltIProvide.EcCQwybvWB3iNxIv9FwsPJEWhR/ywZ6 </code></pre> <p>We could have created the same hash by using crypt directly, which is precisely what <code>password_hash()</code> does behind the scenes.</p> <pre><code>$hash = crypt('password', '$2y$10$ThisIsTheSaltIProvide.'); // $hash = $2y$10$ThisIsTheSaltIProvide.EcCQwybvWB3iNxIv9FwsPJEWhR/ywZ6 </code></pre> <p>The hash consists of:</p> <ul> <li>Algo information: $2y$ (BLOWFISH)</li> <li>Cost param: 10</li> <li>An extra $ </li> <li>The salt: ThisIsTheSaltIProvide.</li> </ul> <p>Using that information, <code>password_verify()</code> reproduces the hash and then compares it to the persisted hash, like so:</p> <pre><code>$existingHash = $2y$10$ThisIsTheSaltIProvide.EcCQwybvWB3iNxIv9FwsPJEWhR/ywZ6 $testHash = crypt('password', '$2y$10$ThisIsTheSaltIProvide.'); // if $existingHash and $testHash match, then the password is good </code></pre> <p>A new, additional salt never comes into play.</p> <p>Additionally, using RANDOM salts is important. If everyone used the same salt, then users with the same password would also have the same hash. No one wants that.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload