将旧密码移动到新的哈希算法?

时间:2013-01-18 13:13:32

标签: security passwords

我正在将网站切换到rails。这是一个拥有5万多用户的大型网站。问题是,现有的密码哈希方法弱。我有两个选择:

1)切换到新算法,为每个人生成随机密码,然后通过电子邮件将这些密码发送给他们,然后立即要求更改

2)实现新算法但之前使用旧算法然后散列结果。例如:

密码:abcdef =算法1 => xj31ndn =算法2 => $ 21aafadsada214

任何新密码都需要通过原始算法(md5)然后如果有任何意义那么得到散列的结果?这有什么不利吗?

4 个答案:

答案 0 :(得分:21)

通常没有必要重置密码,可以等到用户下次登录。

  1. 首先尝试使用新算法验证输入的密码。新密码和已转换的密码不会花费更长时间进行验证。
  2. 如果不匹配,请将其与旧的哈希算法进行比较。
  3. 如果旧的哈希值匹配,那么您可以计算并存储新哈希,因为您知道密码。
  4. 每个密码存储系统都必须具有切换到更好的哈希算法的选项,您的问题不是一次性迁移问题。良好的密码哈希算法(如BCrypt)有一个成本因素,有时你必须增加这个成本因素(因为硬件速度更快),那么你需要完全相同的程序来进行迁移。

    如果您的第一个算法非常弱,并且希望立即提供更多保护,那么使用散列旧散列的选项2是一件好事。在这种情况下,您可以计算双哈希并使用新的双哈希替换数据库中的旧哈希。

    $newHashToStoreInTheDb = new_hash($oldHashFromDb)
    

    您还应该标记此密码哈希(see why),以便将其识别为双哈希。这可以在单独的数据库字段中完成,也可以包含您自己的签名。现代密码哈希函数还包括算法的签名,以便它们可以升级到更新的算法,并且仍然可以验证较旧的哈希值。该示例显示了BCrypt哈希的签名:

    $2y$10$nOUIs5kJ7naTuTFkBy1veuK0kSxUFXfuaOKdOKf9xYT0KKIGSJwFa
    ___
     |
     signature of hash-algorithm = 2y = BCrypt
    

    验证将如下运行:

    1. 决定是否为双重哈希。
    2. 如果是新哈希,请调用新的哈希函数来验证输入的密码,然后就完成了。
    3. 如果是双哈希,请将其与双哈希算法new_hash(old_hash($password))进行比较。
    4. 如果双哈希值匹配,那么您可以计算并存储新哈希值。

答案 1 :(得分:10)

最简单的解决方案可能是向数据库添加“密码哈希类型”列。最初设置为“旧”;当用户登录时,使用新算法重新散列密码并将数据库类型设置为“new”。

此方法的一种变体是将散列类型存储为哈希字符串的部分。这也是有效的,只要您可以明确地区分不同的哈希格式,并且还有一个优点,即您还可以包含任何其他所需的参数(例如salt和{{3}的工作因子})在相同的字符串中,无需为数据库添加额外的字段。

例如,这是key stretching通常使用的方法(以及modern Unix crypt(3) implementations等各种高级语言中的相应函数):一个经典的基于DES(并且非常弱)的密码哈希看起来像abJnggxhB/yWI,而(稍微)更现代的哈希可能看起来像$1$z75qouSC$nNVPAk1FTd0yVd62S3sjR1,其中1指定了哈希方法,z75qouSC是盐和{{1}选择了实际的哈希值和分隔符nNVPAk1FTd0yVd62S3sjR1,因为它不能出现在旧式DES哈希中。


您建议的方法,其中新哈希值计算如下:

$
在某些情况下,

可以有用,因为它允许更新所有现有记录而无需等待用户登录。但是,如果旧的哈希函数保留了足够的熵密码。

例如,即使是一个相当古老和弱的加密哈希函数,如无条件的PHP,也会足够好,因为它的输出取决于整个输入并且具有高达128位的熵,这超过了几乎所有的密码都会有(并且足以承受蛮力攻击)。另一方面,尝试使用旧的基于DES的crypt(3)函数作为旧哈希应用此构造将是灾难性的,因为旧的crypt(3)将忽略除前8个字符之外的所有字符每个密码(以及甚至这些字符的最高位)。

答案 2 :(得分:2)

您可以使用新密码方法更新其密码的所有用户创建新密码字段,并使用您的选项2更新所有人。

结合使用旧密码方法为所有用户登录时强制更新密码将自动将所有活动用户移动到新密码方法。

答案 3 :(得分:1)

另一种方法是在数据库的不同列中保留两个哈希值用于迁移阶段:

  • 如果在登录期间新哈希不存在,请检查旧哈希并保存新哈希并删除旧哈希。
  • 如果新哈希存在,请仅使用此方法进行验证。

因此,经过一段时间后,您将只留下新的哈希值 - 至少对于那些至少登录过一次的用户而言。