密码哈希 - 如何升级?
关于最佳算法有很多讨论 - 但如果您已经投入生产怎么办?如何在不重置用户的情况下升级?
编辑/免责声明:虽然我最初想要一个“快速修复”解决方案并选择了 orip 的响应,但我必须承认,如果应用程序中的安全性足够重要,甚至需要担心这个问题,那么快速修复是错误的心态,他提出的建议解决方案可能不充分。
There's plenty of discussion on the best algorithm - but what if you're already in production? How do you upgrade without having to reset on the user?
EDIT/DISCLAIMER: Although I originally wanted a "quick fix" solution and chose orip's response, I must concede that if security in your application is important enough to be even bothering with this issue, then a quick fix is the wrong mentality and his proposed solution is probably inadequate.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
一种选择是让您存储的哈希包含算法版本号 - 因此您从算法 0(例如 MD5)开始并存储,
然后当您升级到 SHA-1 时,您将版本号更改为 1:(
不,我知道这些长度可能是不对的)。
这样您就可以随时知道在验证密码时要检查哪个版本。您只需擦除以该版本号开头的存储的哈希值即可使旧算法失效。
如果您已经在生产中获得了没有版本号的哈希值,只需选择一种方案,以便您可以轻松识别未版本化的哈希值 - 例如,使用上面的冒号方案,任何不包含版本号的哈希值根据定义,包含冒号的 t 必须早于版本控制方案,因此可以推断为版本 0(或其他版本)。
One option is to make your stored hash include an algorithm version number - so you start with algorithm 0 (e.g. MD5) and store
then when you upgrade to SHA-1, you bump the version number to 1:
(no, I know these lengths probably aren't right).
That way you can always tell which version to check against when validating a password. You can invalidate old algorithms just by wiping stored hashes which start with that version number.
If you've already got hashes in production without a version number, just choose a scheme such that you can easily recognise unversioned hashes - for example, using the above scheme of a colon, any hash which doesn't contain a colon must by definition predate the versioning scheme, so can be inferred to be version 0 (or whatever).
保护所有现有密码的一种很酷的方法:使用现有的哈希值作为新的、更好的密码哈希值的输入。
因此,如果您现有的哈希值是直接 MD5,并且您计划转向某种形式的 PBKDF2 (或bcrypt,或 scrypt),然后将您的密码哈希更改为:
您的数据库中已经有 MD5,因此您只需对其应用 PBKDF2 即可。
其效果良好的原因是 MD5 相对于其他哈希(例如 SHA-*)的弱点不会影响密码的使用。例如,它的冲突漏洞对于数字签名来说是毁灭性的,但它们不会影响密码哈希。与较长的散列相比,MD5 以其 128 位输出在一定程度上减少了散列搜索空间,但这与小得多的密码搜索空间本身相比微不足道。
使密码哈希变得强大的是减慢速度(在 PBKDF2 中通过迭代实现)和随机的、足够长的盐 - 初始 MD5 不会对它们中的任何一个产生不利影响。
当您这样做时,也将版本字段添加到密码中。
编辑:密码学 StackExchange 有一个有趣的讨论 关于此方法。
A cool way to secure all the existing passwords: use the existing hash as the input for the new, and better, password hash.
So if your existing hashes are straight MD5s, and you plan on moving to some form of PBKDF2 (or bcrypt, or scrypt), then change your password hash to:
You already have the MD5 in your database so all you do is apply PBKDF2 to it.
The reason this works well is that the weaknesses of MD5 vs other hashes (e.g. SHA-*) don't affect password use. For example, its collision vulnerabilities are devastating for digital signatures but they don't affect password hashes. Compared to longer hashes MD5 reduces the hash search-space somewhat with its 128-bit output, but this is insignificant compared to the password search space itself which is much much smaller.
What makes a password hash strong is slowing down (achieved in PBKDF2 by iterations) and a random, long-enough salt - the initial MD5 doesn't adversely affect either of them.
And while you're at it, add a version field to the passwords too.
EDIT: The cryptography StackExchange has an interesting discussion on this method.
等到您的用户登录(这样您就有明文的密码),然后使用新算法对其进行哈希处理将其保存在您的数据库中。
Wait until your user logs in (so you have the password in plaintext), then hash it with the new algorithm & save it in your database.
一种方法是:
然后逐渐您将仅拥有以下密码新的哈希值
One way to do it is to:
Then gradually you will have only passwords with the new hash
您现在可能无法更改密码哈希方案,除非您以纯文本形式存储密码。您可以做的是在每个用户成功登录后使用更好的哈希方案重新哈希会员密码。
您可以尝试以下操作:
首先向您的会员表或任何表中添加一个新列存储密码。
接下来,在验证用户身份的代码中,添加一些额外的逻辑(我使用的是 PHP):
您的authenticateUser() 函数需要更改为与此类似的内容:
这种方法有优点也有缺点。好处是,个人成员的密码在登录后变得更加安全。缺点是每个人的密码都不安全。
我只会这样做大约两周。我会向所有会员发送一封电子邮件,并告诉他们由于网站升级,他们有 2 周的时间登录帐户。如果他们在两周内无法登录,他们将需要使用密码恢复系统来重置密码。
You probably can't change the password hashing scheme now, unless you're storing passwords in plain text. What you can do is re-hash the member passwords using a better hashing scheme after each user has successfully logged in.
You can try this:
First add a new column to your members table, or which ever table stores passwords.
Next, in your code that authenticates users, add some additional logic (I'm using PHP):
Your authenticateUser() function would need to be changed to something similar to this:
There's upsides and downsides to this approach. On the upsides, an individual member's password becomes more secure after they've logged in. The downside is everyone's passwords aren't secured.
I'd only do this for maybe 2 weeks. I'd send an email to all my members, and tell them they have 2 weeks to log into their account because of site upgrades. If they fail to log in within 2 weeks they'll need to use the password recovery system to reset their password.
只需在下次验证时重新散列纯文本即可。哦,使用 SHA-256 以及 base256(全字节)和 256 字节大小的盐。
Just re-hash the plain text when they authenticate the next time. Oah and use SHA-256 with a salt of base256 (full byte) and 256 bytes in size.