【问题标题】:Migrate from SHA256 hashed passwords to BCRYPT in PHP7+MySQL在 PHP7+MySQL 中从 SHA256 散列密码迁移到 BCRYPT
【发布时间】:2019-10-30 10:35:42
【问题描述】:

我有一个旧的 Web 应用程序,其中注册了几个用户,它使用不安全的 hash("sha256", trim($_POST["password"])) 将散列密码存储在 MySQL 数据库中。现在我想更新 Web 应用程序以使用更安全的 BCRYPT password_hash() 但是我不想给所有注册用户发送电子邮件,提醒他们更改密码。所以我正在考虑以这种方式在 sha256() 散列密码上实现 BCRYPT:

为了保存密码,我将对用户密码进行 sha256() 哈希处理:

$hashed_password = password_hash(hash("sha256", trim($_POST["password"])), PASSWORD_BCRYPT);

然后我将 BCRYPT 哈希密码保存在数据库中。

为了验证用户的密码,我只需这样做:

$hashed_password = "select hashed_password from users where email = 'abc@email.com'";

if(password_verify(hash("sha256", trim($_POST["password"])), $hashed_password))
{
    echo "Welcome";
}
else
{
    echo "Wrong Password!";
}

这样,我将通过循环每个注册用户来更新 MYSQL 数据库中的用户密码,然后我将检索 sha256() 散列密码,最后我将在使用 password_hash( 进行 BCRYPTed 后重新保存它):

$new_password = password_hash($old_sha256_hashed_password, PASSWORD_BCRYPT);

$mysql->save_user_password($new_password, $user_id);

因此用户仍然可以使用旧密码登录。

你觉得这个解决方案怎么样?

即使我在 BCRYPT 之前对密码进行 sha256() 哈希处理,它仍然安全吗?

【问题讨论】:

  • 如果您没有用户密码,则无法重新散列。只有在用户登录时您才知道密码,然后您可以重新散列它。
  • @Dharman 我知道,这就是为什么我在 BCRYPT 之前对用户密码进行 sha256() 哈希处理,因此经过 sha256() 哈希处理的旧保存密码仍然适用于老用户。我现在对此进行了测试,一切正常,旧的 sha256() 散列密码一旦转换为 BCRYPT 就可以正常工作。我只需要知道它是否仍然安全可靠,因为我在 BCRYPT 之前对用户的密码进行了 sha256() 哈希处理。
  • 让我改写一下:将用户的密码完全重新散列到新系统是个好主意。每次用户使用旧方法登录时,都会重新散列他的密码。我认为无限期地保留这个双重系统没有意义,但暂时可能是个好主意。如果您不想强制用户更改密码,您至少可以在下次登录时为他们重新设置密码。
  • 啊,我明白了,谢谢,是的,这是个好建议,我会实施的。

标签: php mysql passwords bcrypt sha256


【解决方案1】:

由于您当前的哈希系统(未加盐的 SHA256)确实非常不安全,您可以使用双重哈希立即保护密码。尽快,当用户下次登录时,我会切换到新算法并删除双重哈希。

让旧的哈希值更安全:

$doubleHashToStoreInDb = password_hash($oldUnsaltedSha256HashFromDb, PASSWORD_DEFAULT);

对每一行执行此操作将保护否则不安全地存储的密码。注意PASSWORD_DEFAULT 参数,它应该优于特定算法,因为它是面向未来的。并标记双哈希,以便区分双哈希和已转换的哈希,see why

处理新用户注册:

$hashToStoreInDb = password_hash($_POST['password'], PASSWORD_DEFAULT);

只需使用新算法,无需双重哈希。

验证登录:

if (checkIfDoubleHash($storedHash))
{
  $correctPassword = password_verify(oldPasswordHash($_POST["password"]), $storedHash);
  if ($correctPassword)
    storeConvertedHash(password_hash($_POST['password'], PASSWORD_DEFAULT));
}
else
{
  $correctPassword = password_verify($_POST['password'], $storedHash);
}

// Hashes the user password with a deprecated hashing scheme
function oldPasswordHash($password)
{
  return hash("sha256", trim($password));
}

双重哈希将转换为新密码哈希函数,这是可能的,因为我们此时拥有原始用户密码。新的哈希值通过password_verify() 进行验证,这是一个面向未来且向后兼容的函数。

使密码算法适应未来的硬件不是一次性的任务,一旦新硬件变得更快,这将是必要的。 PHP 提供了函数password_needs_rehash() 来判断是否需要重新散列,然后你也可以计算一个新的散列并存储它。

【讨论】:

    猜你喜欢
    • 2016-12-11
    • 2013-04-24
    • 2011-08-10
    • 2012-06-02
    • 1970-01-01
    • 2021-05-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多