在不要求所有用户更改密码的情况下对密码进行散列处理


Rehashing passwords without asking all users to change them

前开发人员使用PHP hash()函数与SHA256算法存储密码哈希值。为了提高系统的安全性,我想开始使用crypt()与Blowfish算法(不幸的是,我们没有PHP 5.5,因此password_hash()不可用)。

由于SHA256是一种不可逆的哈希算法,是否有一种方法可以开始使用crypt()与盐密码,而不要求每个人重置他们的密码?

那么您应该使用兼容性库。当你升级到5.5的时候会更方便。

重新哈希而不要求用户输入密码…那么,您可以等到下次用户登录时,然后使用password扩展的password_verify()功能。如果它失败了,那么你可以回到旧的SHA256哈希。如果SHA256哈希匹配,那么你可以使用password_hash()重新哈希密码,并将其保存在旧哈希的位置:

if (password_verify($password, $hash)) {
    // Matches...
} elseif (hash('sha256', $password) == $hash) {
    // Matches...
    $newHash = password_hash($password);
    // Save $newHash in the old hash's place
} else {
    die('Invalid password...');
}

技术上可以破解很多哈希,但是有太多的问题(你不会得到所有的哈希,它很可能是不可行的,它甚至可能是不合法的,等等)。

您可能要考虑的另一种方法是哈希链:由于您无法逆转SHA256,只需将新的哈希函数定义为crypt(sha256($passwd))。由于您可能已经在文件中为所有密码设置了sha256($passwd),因此可以使用适当的salt对每个密码设置crypt()以更新现有的散列(而不必等待用户登录)。

这是一个可能的解决方案:

在用户表中添加一列,表示对用户密码使用了哪种散列方法。在登录时,您将知道用户的密码,因为他刚刚输入了密码,因此,一旦传递了当前哈希,就从密码中创建一个新的has并更新标志列

这假设你在互联网上传递自由文本密码,除非你使用SSL,否则你不应该这样做。

或者,如果您在发送密码之前在客户端上散列,则更新客户端软件以处理两种散列算法并同时发送。使用您的标志来确定要检查的内容。

在这两种情况下,一旦所有(或大多数)用户都切换了,就删除旧的哈希,并将此问题强加给剩余的用户。

我假设您从未存储明文用户帐户密码,因为这确实是一件很糟糕的事情。因此,您不再拥有创建新密码摘要所需的数据。

我想你会需要每个人更新他们的密码。

可能有其他更快更有效的方法来做到这一点,但如果您想在不影响用户的情况下做到这一点,我将这样做-

在表中添加另一个列,一个可以为True或False的基本标志。默认为false。然后实现以下伪代码:

if(flag=true)
{
 use crypt() and authenticate user
}
else
{
use hash() and authenticate user
use crypt() on the provided password (once authenticated)
update the record to put the new password into the table
set flag=true
}

本质上它检查密码是否更新,如果没有更新则更新。一旦用户完成了转换,您最终可以取消此功能。但由于它几乎没有增加负载,我建议保留它!

这有点迂回,但它将有最少的工作,为您的用户做,它将在后台运行,没有给他们任何指示发生!

我建议使用一个标记字段来注释哪些用户先前已被散列,然后对现有的散列进行加密。对于任何在身份验证时标记字段为true的人来说,它变成了一个两步的过程,对密码进行散列,然后加密以进行匹配检查。

当他们更新密码时,您将把标记字段设置为false。

是的,您需要做的是添加一个额外的列来存储crypt()输出。当一个用户登录,并且他们的密码成功地hash()es到您在数据库中拥有的密码时,您现在可以crypt()该密码,并从数据库中删除旧的hash

这只在用户登录时起作用,所以你会有一段时间,有些用户在使用旧系统,有些用户在使用新系统。