如何升级密码存储方案(更改哈希算法)
我被要求对 Intranet 站点进行一些更改/更新;正如他们所说,使其成为“面向未来”。
我们发现密码是使用 MD5 算法进行哈希处理的。 (该系统自 2001 年以来就已经存在,所以当时已经足够了)。
我们现在想要将哈希算法升级为更强的算法(BCrypt-hash 或 SHA-256)。
我们显然不知道明文密码,并且为用户库创建新密码不是一个选项*)。
所以,我的问题是:
在无法访问明文密码的情况下更改哈希算法的可接受方法是什么?
最好的解决方案是完全“在幕后”的解决方案。
<子> *)我们尝试过;为了说服他们,我们使用了“密码年龄”的论点,试图用咖啡贿赂他们,试图用蛋糕贿赂他们等等。但这不是一个选择。
更新
我希望有某种自动解决方案来解决问题,但显然除了“等待用户登录,然后转换”之外没有其他选择。
好吧,至少现在我现在没有其他的解决办法了。
I've been asked to implement some changes/updates to an intranet-site; make it 'future proof' as they call it.
We found that the passwords are hashed using the MD5 algorithm. (the system has been around since 2001 so it was adequate at time).
We would now like to upgrade the hashing-algorithm to a stronger one (BCrypt-hash or SHA-256).
We obviously do not know the plaintext-passwords and creating a new password for the userbase is not an option*).
So, my question is:
What is the accepted way to change hashing-algorithm without having access to the plaintext passwords?
The best solution would be a solution that is entirely 'behind the scenes'.
*) we tried; tried to convince them, we used the argument of 'password age', tried to bribe them with coffee, tried to bribe them with cake, etc. etc. But it is not an option.
Update
I was hoping for some sort of automagic solution for solving the problem, but apparently there are no other options than just 'wait for the user to log in, then convert'.
Well, at least now I now there is no other solution available.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
首先,在数据库中添加一个字段来识别密码是使用MD5还是新算法。
对于仍然使用 MD5 的所有密码:
-- 在登录过程中,验证用户输入的密码:将用户提交的密码临时存储在内存中(这里没有安全问题,因为它已经在内存中的某处)并执行通常的 MD5 哈希&与存储的哈希值进行比较;
-- 如果给出了正确的密码(与现有哈希匹配),则通过新算法运行临时存储的密码,存储该值,更新新字段以标识该密码已更新为新算法。
(当然,您只需对任何新用户/新密码使用新算法。)
First, add a field to the DB to identify whether or not the password is using MD5 or the new algorithm.
For all passwords still using MD5:
-- In the login process, where you verify a user's entered password: temporarily store the user's submitted password in memory (no security issue here, as it is already in memory somewhere) and do the usual MD5 hash & compare with the stored hash;
-- If the correct password was given (matches the existing hash), run the temporarily stored password through the new algorithm, store that value, update the new field to identify that this password has been updated to the new algorithm.
(Of course you would just use the new algorithm for any new users/new passwords.)
我不完全确定这个选项,因为我不是密码学专家。如果我在某些地方错了,请纠正我!
我认为 Dave P. 显然是最好的选择。
... 但。有一个自动解决方案 - 对旧的哈希值本身进行哈希处理。也就是说,获取当前的哈希值,并使用更强的算法再次对它们进行哈希处理。请注意,据我了解,这里的哈希长度不会增加任何安全性,只会增加新算法的加密复杂性。
当然,问题是检查密码必须通过两个哈希值。您还必须对每个新密码执行相同的操作。嗯,这非常愚蠢。除非您想使用像 Dave P. 解释的类似方案,最终使用新的哈希算法返回到单哈希密码……在这种情况下,为什么还要为此烦恼呢? (当然,您可能会在公司诉讼的演示中以一种华丽的“提高所有密码的安全性,立即应用!”的方式使用它,并且表情相对严肃......)
尽管如此,它仍然是一个可以立即应用的选项所有当前密码,无需任何逐步迁移阶段。
但是天哪,天哪,以后有人看到这段代码会开怀大笑吗! :)
I'm not entirely sure about this option, since I'm not an expert on cryptography. Please correct me if I'm wrong at some point here!
I think Dave P. has clearly the best option.
... but. There is an automagic solution - hash the older hashes themselves. That is, take the current hashes, and hash them again with a stronger algorithm. Notice that as far as I understand, you don't get any added security from hash length here, only the added cryptographical complexity of the new algorithm.
The problem is, of course, that checking a password would then have to go through both hashes. And you'd have to do the same for evey new password as well. Which is, well, pretty much silly. Unless you want to use a similar scheme like Dave P. explained to eventually graduate back to single-hashed passwords with the new hashing algorithm... in which case, why even bother with this? (Granted, you might use it in a flashy "Improved security for all passwords, applied immediately!"-way at a presentation to corporate suits, with a relatively straight face...)
Still, it's an option that can be applied immediately to all current passwords, without any gradual migration phase.
But boy, oh boy, is someone going to have a good laugh looking at that code later on! :)
将passwordChange日期时间字段添加到数据库中。
X 天之前设置的所有密码,使用 MD5 检查
X 天之后设置的所有密码,使用 BCrypt 或其他方式检查。
Add passwordChange datetime field to the database.
All password set before day X, check using MD5
All passwords set after day X, check using BCrypt or whatever.
您可以将用于创建该哈希的算法存储在哈希字段本身(例如“MD5:d41d8cd98f00b204e9800998ecf8427e”)或另一列中。然后,您必须修改登录过程,以便在检查密码时使用正确的算法。当然,任何新密码都将使用新算法进行哈希处理。希望密码最终会过期,并且随着时间的推移,所有 MD5 哈希值都将被逐步淘汰。
You could store, either in the hash field itself (e.g. "MD5:d41d8cd98f00b204e9800998ecf8427e") or in another column, which algorithm was used to create that hash. Then you'd have to modify the login process to use the correct algorithm when checking the password. Naturally, any new passwords will be hashed using the new algorithm. Hopefully, passwords eventually expire, and over time all of the MD5 hashes will be phased out.
由于您不知道明文密码,也许您应该创建一个指示加密版本的字段(例如
PasswordVersion位默认0
)下次用户尝试登录时,使用当前算法版本检查散列密码,就像你今天做的那样。如果匹配,则再次对其进行哈希处理并更新
PasswordVersion
字段。希望您不需要比
bit
大的PasswordVersion
列。 =)Since you don't know plaintext password, maybe you should to create a field which indicates encription version (like
PasswordVersion bit default 0
)Next time user tries to log in, check hashed password using current algorithm version, just like you do today. If it matches, hash it again and update
PasswordVersion
field.Hopefully you'll not need a
PasswordVersion
column bigger thanbit
. =)您应该更改密码数据库以存储 3 项:
当然,这些可以用分隔符一起存储在一个文本字段中:
现在将现有条目转换为具有空盐和旧算法的值
现在您有足够的信息来验证所有现有的密码条目,但您也可以验证新条目(因为您知道使用了哪个哈希函数) 。您可以在现有用户下次登录时将旧条目转换为新算法,因为在此过程中您将获得他们的密码:
最终,在该系统运行一段合适的时间后,您可以禁用尚未转换的帐户(如果需要)。
添加每个条目独有的随机盐字符串使得该方案更能抵抗使用彩虹表的字典攻击。
You should change your password database to store 3 items:
Of course these could just be stored together in one text field with a delimiter:
Now convert you existing entries to a value with empty salt and the old algorithm
Now you have enough information to verify all you existing password entries, but you can also verify new entries (since you know which hash function was used). You can convert the old entries to the new algorithm the next time the existing users login since you will have their password available during this process:
Eventually, after this system has been running for a suitable time, you can disable accounts that haven't been converted (if desired).
The addition of a random salt string unique to each entry makes this scheme much more resistent to dictionary attacks using rainbow tables.
最佳答案来自真正的密码学专家
https://paragonie.com/ blog/2016/02/how-safely-store-password-in-2016#legacy-hashes
这篇文章还有助于解释您应该使用哪种哈希。即使它写着 2016,它仍然是最新的。如果有疑问,请使用 bcrypt。
在您的用户帐户表中添加一列,称为legacy_password(或同等内容)。这只是一个布尔值
,计算现有密码哈希值的新的更强的哈希值并将它们存储在数据库中。
修改您的身份验证代码以处理旧标志。
当用户尝试登录时,首先检查是否设置了legacy_password标志。如果是,请首先使用旧密码哈希算法对其密码进行预哈希,然后使用此预哈希值代替其密码。然后(md5),重新计算新的哈希值并将新的哈希值存储在数据库中,在此过程中禁用legacy_password标志。
The best answer is from an actual cryptography expert
https://paragonie.com/blog/2016/02/how-safely-store-password-in-2016#legacy-hashes
This post also helps explain which hashing you should use. It's still current even if it says 2016. If in doubt use bcrypt.
Add a column to your user accounts table, called legacy_password (or equivalent). This is just a Boolean
Calculate the new stronger hash of the existing password hashes and store them in the database.
Modify your authentication code to handle the legacy flag.
When a user attempts to login, first check if the legacy_password flag is set. If it is, first pre-hash their password with your old password hashing algorithm, then use this prehashed value in place of their password. Afterwards (md5), recalculate the new hash and store the new hash in the database, disabling the legacy_password flag in the process.