从未加盐的 MD5 密码变为加盐的 MD5 密码
我有一个 LAMP (PHP) 网站,该网站越来越受欢迎。
为了安全起见,我将用户密码存储为 md5 哈希值。
但我现在发现这并不安全;我应该对 md5 哈希值加盐 - 因为目前可以使用彩虹表解码未加盐的 md5 哈希值。
我能做些什么?
我不想让每个人都输入新密码。
I have a LAMP (PHP) website which is becoming popular.
I played it safe by storing the user passwords as md5 hashes.
But I now see that's not secure; I should have salted the md5 hash - because it's currently possible to decode unsalted md5 hashes using rainbow tables.
What can I do?
I don't want to make everyone type a new password.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(12)
您可以执行“两步哈希”,而不是在一步中创建哈希。
您可以将每个密码哈希附加到用户名中,然后再次对其进行哈希处理。这将创建一个不可解密的哈希值,其中包含独特的信息。
通常的腌制过程是
salt+PWD->Salt+PWD。哈希
你可以这样做:
密码 ->哈希->用户ID+哈希->哈希
(请注意,仅选择了 UserID,因此每个双哈希都存在唯一的盐...随意使您的盐更复杂)
You can do a "2 step hashing" instead of creating a hash in a single step.
You could append each password hash to the username, and then hash it again. This will create an undecryptable hash thats salted with unique informations.
The usual process of salting is
salt+PWD -> hash
You could do something like:
PWD -> Hash -> UserID+Hash -> Hash
(Note the UserID was only picked so a unique salt for each double hash exists... Feel free to make your salt more complex)
你可以在飞行中给它们加盐。添加一段代码,以便当有人登录时,它会执行正常过程(计算密码的 MD5 和并根据存储的哈希进行检查),如果成功,则从明文重新计算哈希的加盐版本他们输入的文本密码,并将其存储在密码文件中。
唯一的问题是,您需要添加一个指示符来指示每个 MD5 是否加盐,因为您将在一段时间内混合使用两者。或者,为了稍微降低安全性,您可以检查每个加盐和未加盐的密码,如果其中一个密码命中,则接受登录。当然,如果您检测到它没有加盐,那么您就可以在此时升级。
You can salt them on the fly. Add a piece of code so that, when someone logs in, it does the normal process (computes the MD5 sum of the password and checks it against the stored hash) and if that succeeds, recompute a salted version of the hash from the clear-text password they entered, and store it in the password file.
The only wrinkle is that you'll need to add an indicator for whether each MD5 is salted or not, since you'll have a mix of both for a while. Or, for a minor loss of security, you can check each password salted and unsalted and if either one hits, accept the login. Of course, if you detect that it was unsalted, then you upgrade at that point.
答案很简单,确保在新的哈希系统上保留哪些用户拥有密码的记录或某种标志,当他们下次登录时,对他们进行身份验证,计算新的哈希值,翻转标志。
现在,每当有人登录并设置标志时,就使用新的哈希对其进行身份验证。
The answer is simple, make sure the keep a record or some sort of flag of which users have passwords on the new system of hashing, when they next login, authenticate them, calculate the new hash, flip the flag.
Now whenever someone logs in and the flag is set, authenticate them with the new hash.
为什么不向您的用户表添加一个新列
new_pwd
,该列存储md5($originallyHashOfPwd . $salt)
的结果。然后,您可以预先计算new_pwd
,完成后调整您的登录检查,将md5(md5($entered_pwd) . $salt)
的结果与new_pwd 中的结果进行比较
。完成切换登录检查后,删除旧列。这应该可以阻止彩虹表式的攻击。
Why not add a new column
new_pwd
to your user table, which stores the result ofmd5($originallyHashOfPwd . $salt)
. You can then precomputenew_pwd
and once that's done adjust your login checking to compare the result ofmd5(md5($entered_pwd) . $salt)
to what's innew_pwd
. Once you're done switching your login checking, delete the old column.That should stop rainbow-table style attacks.
您仍然可以使用盐。只需根据当前哈希值和盐计算另一个哈希值:
对于新密码,您需要使用:
You can still use a salt. Just calculate another hash from the current hash together with a salt:
For new passwords you then need to use:
更新密码并使其更安全的一个好方法是更改为使用加盐 SHA1 作为密码。 SHA1 更难产生冲突,而且它的字符串长度也与 MD5 不同。 MD5 的长度为 32 个字符,而 SHA1 的长度为 40 个字符。
要在 PHP 中转换这些内容,首先检查存储密码的字符串长度。如果长度为 32 个字符,请使用旧方法检查密码,然后使用 SHA1 向数据库写入一个新密码。
如果我没记错的话,这正是 WordPress 处理此问题的方式。
A great way to update the passwords while also making them more secure is to change to using a salted SHA1 for passwords. A SHA1 is harder to create a collision against, and it also has a different string length to MD5. A MD5 is 32 characters long, while a SHA1 is 40 characters long.
To convert these in PHP, you first check the string length of the stored password. If it is 32 characters long, check the password using your old method and afterwards, write a new one using SHA1 to the database.
If I remember correctly, this is precisely how WordPress handled this issue.
用户下次登录时动态重新加密密码,即先检查密码是否正确,然后用盐加密并再次存储。
Dynamically re-encrypt the passwords when the users log in the next time, i.e. first check whether it’s correct, afterwards encrypt it with a salt and store it again.
您可以通过在表中添加一列来存储新格式来迁移密码。
当用户登录成功后,如果新列为空,则将更强的密码放入其中,并清空原始列。如果新列有一个条目,请将输入与其中的值进行比较。
You can migrate the passwords by adding a column in your tables to store the new format.
When a user logs in successfully, if the new column is empty, put the stronger password in there and empty out the original column. If the new column has an entry, compare the input to the value in there.
这里有两个选项
据我所知,没有其他方法可以恢复密码。
编辑:
虽然 MD5 是一个哈希并且不应该是可解码的,但它可以使用彩虹表来破解:概率几乎为 1,您可以找到一个唯一的(这里是概率)字符串,最多包含 20 个字符,并且具有给定的哈希,特别是如果您的字符集仅限于字母数字。严格来说,这不是解码。出于所有实际目的,确实如此。
额外注意:生成彩虹表,查找 1000 个密码仍然需要花费很多时间。
Two options here
As far as I can see, there is no other way of recovering the passwords.
EDIT:
Although MD5 is a hash and should not be decodable, it can be broken using rainbow tables: with probability almost one, you can find a unique (here's the probability) string of at most, say, 20 characters with a given hash, especially if your character set is limited, say, to alphanumeric. Strictly speaking, this is not decoding. For all practical purposes, it is.
Extra note: producing the rainbow tables, and looking up 1000 password is still going to take a lot of time.
正如其他人提到的,对原始哈希加盐。这里有几点提示:
Salt the original hash as mentioned by others. Just a few pointers here:
如果您要放弃 MD5,您应该跳过简单的加盐,而采用一种更好的技术,称为拉伸。特别是,您应该使用 bcrypt(用 php 实现为 PHPASS)。
这里有一个关于为什么 bcrypt 的很好的链接:http://chargen.matasano.com/chargen/2007/9/7/enough-with-the-rainbow-tables-what-you-need-to- know-about-s.html
下面是一个简短的操作方法:
1.下载phpass包:http://www.openwall.com/phpass/
2. 查看 test.php 中的示例,如下所示:
如果 $check===true (即上面的情况),则密码正确。
如果您的密码是“hello”,您将使用 HashPassword 对其进行哈希处理,将哈希值放入数据库中,当用户登录时,调用 CheckPassword(userenteredpassword,hashInDb) 来查看密码是否正确
If you're moving away from MD5, you should go skip simply salting and go to an even better technique called stretching. In particular you should use bcrypt (implemented as PHPASS with php).
Here is a great link on why bcrypt: http://chargen.matasano.com/chargen/2007/9/7/enough-with-the-rainbow-tables-what-you-need-to-know-about-s.html
And here is a short How To:
1. Download the phpass package: http://www.openwall.com/phpass/
2. Look at test.php for examples like the one below:
If $check===true (which is the case above) then the password is correct.
If your password is 'hello', you would hash it using HashPassword, put the hash in a database, and when a user logs in, call CheckPassword(userenteredpassword,hashInDb) to see if the password is correct
遗憾的是,您唯一的方法是告诉您的用户更新密码。
您也可以生成随机密码,但这同样很麻烦。
编辑
您可以对存储的密码进行双重编码。因此,您的新加盐哈希算法将是:
要更新您的旧密码,请使用
检查提供的密码是否正确,只需使用
sadly, your only way is to tell your users to renew their passwords.
you could also generate random passwords, but that is the same hassle.
edit
you could just double encode your stored passwords. so your new salted hashing algorithm would be:
to update your old passwords use
to check if a provided password is correct simply use