10

PHP 5.5 中新的 password_hash API 很好,我想开始在任何地方使用它。给定一个具有旧数据库的旧项目,其中密码存储在 md5 哈希中,将旧用户密码迁移到新的、更安全的 API 的最佳方法是什么?

除了简单地提示用户在下次登录时重置密码(这对用户来说是不切实际且烦人的)之外,我还考虑过使用当前 md5 哈希作为我所有现有用户的 password_hash() 输入的可能性。要验证这些用户的密码(在登录期间),我会将他们的输入转换为 md5 哈希,然后将其用于 password_verify()。新用户可以省去这个额外的步骤。

这是一个值得的方法吗?有没有更好的透明迁移方法,用户不会因为密码重置而烦恼,但我可以立即享受更安全的散列带来的好处?

最重要的是,采用现有的 md5 哈希(容易被暴力破解)并使用 password_hash() API 来“双重哈希”它是否有安全优势?

4

3 回答 3

13

在您的login.php(?) 中,您将旧密码从 MD5 转换为 bcrypt,并将数据库中的旧 MD5 哈希替换为新密码。

伪代码:

$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));
    }
}

双散列不会增加 bcrypt 的安全性,因为 bcrypt itef 是一种单向散列函数。

注意:MD5 产生一个 32 个字符长度的字符串,而password_hash()最少是 60 个。

阅读手册:

如果并且当您决定使用password_hash()或兼容包(如果 PHP < 5.5)https://github.com/ircmaxell/password_compat/时,请务必注意,如果您当前密码列的长度低于 60,则将需要更改为(或更高)。手册建议长度为 255。

您需要更改列的长度并使用新的哈希重新开始以使其生效。否则,MySQL 将静默失败。

于 2013-09-20T00:03:38.227 回答
2

由于它是一种单向加密,除非您希望在登录页面上输入用户密码,这是不安全的,否则您可以让用户重新输入他们的密码。另一种选择是使用散列密码重新加密所有数据库记录password_hash()并将md5()这些值存储到数据库中,然后在您的登录 PHP 页面上放置password_hash()您的md5(),有点像:

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

使用第二种方式,您不必让用户重置密码。

于 2013-09-20T00:09:00.657 回答
0

有一个非常具体的用例在这里还没有提到,那就是你已经迈出了第一步,开始使用crypt函数,但仍然使用 MD5 算法。

在这种情况下,您在注册/密码更改时的密码哈希将如下所示:

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

然后你会比较:

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

这种转变的美妙之处在于您的数据库已经处于可以使用的状态password_verify

注册/密码更改将变为:

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

您可以将比较替换为:

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

这将开箱即用,并在下次更改密码时升级所有用户的密码。但是我们不需要等待,也可以按照@Fabian 在这里的回答中所做的事情来做。

这里我们只需要更改登录名:

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
  }
}

一旦新密码算法成为 PHP 的默认算法,这将为升级用户密码提供额外的好处。你实际上什么都不用做。

如果您希望为密码哈希函数使用其他参数(例如更改“成本”),您应该查看password_hashpassword_needs_rehash文档,注意可选的最后一个参数$options

于 2015-10-27T15:08:01.597 回答