Converting md5 password hashes to PHP 5.5 password_hash()

坚强是说给别人听的谎言 提交于 2019-11-27 20:51:19
Fabian

In your login.php (?) you convert the old passwords from MD5 to bcrypt and replace the old MD5 hash in the database with the new one.

Pseudo code:

$password = $_POST["password"];

if (substr($pwInDatabase, 0, 1) == "$")
{
    // Password already converted, verify using password_verify
}
else
{
    // User still using the old MD5, update it!

    if (md5($password) == $pwInDatabase)
    {
        $db->storePw(password_hash($password));
    }
}

Double hashing would not increase the security of bcrypt, as bcrypt itsef is a one-way hashing function.

Nota: MD5 produces a 32 character length string, while password_hash() is a minimum of 60.

Read the manual:

If and when you do decide to use password_hash() or the compatibility pack (if PHP < 5.5) https://github.com/ircmaxell/password_compat/, it is important to note that if your present password column's length is anything lower than 60, it will need to be changed to that (or higher). The manual suggests a length of 255.

You will need to ALTER your column's length and start over with a new hash in order for it to take effect. Otherwise, MySQL will fail silently.

Since it is one way encryption, unless you want the users passwords on your login page, which is not secure, you can have the users reenter their passwords. The other option is to reencrypt all of the database records with password_hash() on top of their md5() hashed passwords and store those values to the database, then on your login PHP page put the password_hash() around your md5(), somewhat like:

password_hash(md5($_POST['password']));

Using the second way you don't have to have the user reset their passwords.

There is very specific use case that has not yet been mentioned here, and that is when you have taken a first step already and began to use crypt function, but still using MD5 algorithm.

In that case your password hashing at registration/password change would look like:

$pass_hash = crypt($pass, '$1$salthere');
// store $pass_hash in database

And then you would have comparison with:

if(hash_equals($pass_hash_from_db, crypt($user_input, '$1$salthere')))
{
  // user logged in
}

The beauty of this transition is that your database would already be in the state ready to use password_verify.

The registration/password change would become:

 $pass_hash = password_hash($pass);
 // store $pass_hash in database

And you would substitute comparison with:

if(password_verify($user_input, $pass_hash_from_db))
{
  // user logged in
}

This would just work out of the box, and upgrade all user's passwords at next password change. But we don't need to wait, and do what @Fabian did in one's answer here as well.

Here we need to only change the login:

if(password_verify($user_input, $pass_hash_from_db))
{
  // user logged in
  if(password_needs_rehash($pass_hash_from_db, PASSWORD_DEFAULT))
  {
    $pass_hash = password_hash($user_input);
    // store $pass_hash in database
  }
}

This would serve the added benefit of upgrading user's passwords as soon as the new password algorithm will become PHP's default one. You would actually have to do absolutely nothing.

If you wish to use additional parameters for your password hashing function (such as changing the "cost"), you should look at password_hash and password_needs_rehash documentation, pay attention to optional last parameter $options .

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!