我以前必须两次解决同样的问题:
- 我的第一个 Web 应用程序,我实际上知道足够 MD5 散列用户的密码;然而,我不知道盐,后来才开始研究。
- 几年后,当我决定从现有的 MD5“升级”到 SHA-512 时,实际上是同一个网络应用程序。
在这两种情况下,我都没有使用您的选项,而是使用选项 3:在用户下次登录时,使用密码生成新哈希并替换旧哈希(在验证旧哈希之后)。
在添加盐的情况下,这非常简单:我所做的只是默认每个人都使用“”(空字符串)的盐,可以将其连接起来然后进行散列,而不会对生成的散列产生任何影响;一旦通过身份验证,我为用户生成了一个新的盐,然后重新散列密码,保存新的结果。
从 MD5 升级到 SHA-512 有点棘手,但只需查看表中 has 的字符串长度(我没有为新哈希使用新列,只是扩展现有列以适应更长的哈希)我可以告诉使用哪种算法,然后适当地验证用户;一旦通过身份验证,如果它们仍然在旧哈希上,我会计算一个新的(也借此机会生成一个全新的盐)并存储它。
在这两种情况下,我当然最终都遇到了“旧式”密码仍然存在的情况。在等待适当的时间(例如 6 个月)后,只需确定那些自采用新样式以来尚未登录的人是“不活动的”:为他们生成并存储一个新的、完全随机的密码(使用新样式存储它,当然),如果他们真的回来了,他们将不得不使用您的密码重置机制来重新获得访问权限。(或者,保持原样,但只需删除旧样式的代码即可有效地使其无效。)您也可以(如果适用)向这些用户发送电子邮件,要求他们登录以完成安全升级他们的帐户,在使他们的当前密码无效之前。
当然,这种方法确实涉及身份验证例程中的额外代码,但这只是暂时的——一旦每个人都升级了(无论是通过登录还是像上一段那样被“强制”进入),您就可以删除所有负责的代码执行升级。安全升级完成,您的大多数用户(以及所有普通用户)从未注意到任何事情!