将旧的密码移动到新的散列algorithm?

我正在将一个网站切换到导轨。 这是一个相当大的网站,拥有5万多用户。 问题是,现有的密码哈希方法是非常薄弱的。 我有两个select:

1)切换到一个新的algorithm,为每个人生成随机密码,然后通过电子邮件发送这些密码,并要求立即更改

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

密码:abcdef =algorithm1 => xj31ndn =algorithm2 => $ 21aafadsada214

任何新的密码都需要经过原始algorithm(md5),然后得到散列的结果,如果这是有道理的? 这有什么不利吗?

通常没有必要重置密码,只能等到用户下次login。

  1. 首先尝试使用新algorithmvalidationinput的密码。 然后,新的密码和已经转换的密码不需要更长时间的validation。
  2. 如果不匹配,请将其与旧的散列algorithm进行比较。
  3. 如果旧的散列值匹配,那么你可以计算和存储新的散列,因为你知道密码。

每个密码存储系统必须有select切换到更好的哈希algorithm,您的问题不是一次性迁移问题。 像BCrypt这样的好的密码哈希algorithm有成本的因素,有时你必须增加这个成本因素(因为硬件更快),那么你需要完全相同的程序,你需要迁移。

如果你的第一个algorithm非常弱,并且你想立即给予更多的保护,你的选项2与散列旧的散列是一件好事。 在这种情况下,您可以计算双重散列,并用新的双重散列replace数据库中的旧散列。

$newHashToStoreInTheDb = new_hash($oldHashFromDb) 

你也应该标记这个密码哈希( 看看为什么 ),所以你可以认出它是双哈希。 这可以在单独的数据库字段中完成,也可以包含自己的签名。 现代密码哈希函数还包括algorithm的签名,以便他们可以升级到更新的algorithm,并且还可以validation旧的哈希值。 该示例显示了BCrypt哈希的签名:

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

validation会像这样运行:

  1. 决定是否是双重哈希。
  2. 如果它是一个新的哈希,调用新的哈希函数来validationinput的密码,并完成。
  3. 如果是双重散列,请将其与双重散列algorithmnew_hash(old_hash($password))
  4. 如果双哈希值匹配,那么您可以计算并存储新的哈希值。

最简单的解决scheme可能是在数据库中添加“密码哈希types”列。 最初设置为“旧”; 当用户login时,使用新algorithm对密码进行重新哈希,并将数据库types设置为“新”。

此方法的一个变体是将散列types存储为散列string的一部分 。 这同样适用,只要你可以明确地告诉不同的散列格式,并且你可以在同一个string中包含任何其他需要的参数(比如盐和键拉伸的工作因子)必须为每个数据库添加额外的字段。

例如,这是现代Unix crypt(3)实现 (以及各种高级语言(如PHP )中的相应函数)通常使用的方法:基于经典的基于DES(可怕的弱密码)哈希将看起来像abJnggxhB/yWI ,而一个(稍微)更现代的哈希可能看起来像$1$z75qouSC$nNVPAk1FTd0yVd62S3sjR1 ,其中1指定了哈希方法, z75qouSC是salt, nNVPAk1FTd0yVd62S3sjR1是实际的哈希,并且select了分隔符$ ,因为它不能出现在nNVPAk1FTd0yVd62S3sjR1的哈希表中,样式DES散列。


你build议的方法,新的哈希计算如下:

  hash = new_hash( old_hash( password ) ) 

在某些情况下可以是有用的,因为它允许更新所有现有logging,而不必等待用户login。但是,只有旧的散列函数保留足够的密码熵才是安全的。

例如,即使是一个相当古老而薄弱的密码散列函数,如未encryption的MD5 ,也是足够好的,因为它的输出取决于整个input,并且具有多达128位的熵,这比任何密码都要多无论如何,足以承受powershell攻击)。 另一方面,尝试将这种使用旧的基于DES的crypt(3)函数作为旧散列的构造将是灾难性的 ,因为旧的crypt(3)将忽略除了每个密码的前8个字符以外的所有(以及即使是那些angular色的最重要的位)。

您可以为所有使用新密码方法更新密码的用户创build一个新的密码字段,并使用您的选项2更新每个人。

结合使用旧密码方法强制密码更新login所有用户将自动移动所有活动用户到新的密码方法。

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

  • 如果在login过程中新的哈希值不存在,请检查旧的哈希值并保存新的哈希值并删除旧的哈希值。
  • 如果新的散列存在,只用这个来validation。

因此,在一段时间之后,您将只剩下新的哈希 – 至less对于至lesslogin一次的用户来说。