如何将密码哈希从MD5转换为SHA?

15

我有一个旧应用程序,其中用户密码以MD5哈希的形式存储在数据库中。我想用SHA-2家族中的某种方法来替换它。

我想到了两种可能的方法来实现这一点,但都似乎有些笨重。

1)添加一个布尔型“标志”字段。用户首次进行身份验证后,将MD5密码哈希替换为SHA密码哈希,并设置标志。然后我可以检查该标志以确定密码哈希是否已被转换。

2)添加第二个密码字段以存储SHA哈希。用户首次进行身份验证后,使用SHA对其密码进行哈希并将其存储在新字段中(可能同时删除其MD5哈希)。然后我可以检查SHA字段是否具有值;这基本上变成了我的标志。

在任何情况下,MD5身份验证都必须保留一段时间,以供不经常登录的用户使用。而任何不再活动的用户将永远不会切换到SHA。

有更好的方法来做到这一点吗?


3
你提供的两个解决方案我认为看起来不错。 - wtaniguchi
我支持Ned的回答,他说得很有道理。 - wtaniguchi
5
对于从未更改过的用户 - 在一定比例的用户已经更改并足够时间过去后,我会考虑摆脱MD5哈希。在此期间没有登录的人如果有重新登录,则必须重置他们的密码。是否接受这种决定及何时接受是一个商业决策。 - Michael Burr
2
我在想你是否真的需要一个额外的标志:旧哈希的长度无论如何都更短。 - mark
2
明显的提醒:在验证后别忘了重新生成密码哈希值 :-) - Vinko Vrsalovic
7个回答

11

本质上与添加额外字段相同,但可能更加优雅:在Django的默认认证框架中,密码哈希以构建如下字符串的形式存储:

hashtype$salt$hash

Hashtype可以是sha1或md5,salt是用于对原始密码进行加盐的随机字符串,最后是哈希本身。示例值:

sha1$a1976$a36cc8cbf81742a8fb52e221aaeab48ed7f58ab4

唯一的问题是它以一种明显的方式存储盐,而不是为用户使用另一个独特或派生值(例如他们帐户创建的时间戳的变异版本,或者翻转他们的用户名等)。这是否会对破解所需的时间产生任何当前可行的差异是有争议的,我只是有点偏执。 - defines
@Dustin: 这里的额外优势是,每当用户更改密码时,盐值都可以更改。 - Joshua
但是你正在存储盐。如果我拥有你的数据库和所有哈希值,我也有你的盐。 - defines
1
@Dustin:在这个设置中,盐的作用仅仅是为了使使用彩虹表的攻击无效,因为每个用户的盐都是不同的。 - Jørn Schou-Rode
是的,我理解这个好处,我只是在说我个人更喜欢不存储盐,以便它显然是盐。就像我之前说的,知道盐并不一定使破解密码更可行,但我很谨慎。我为每个用户使用不同的盐,但它是从用户的另一个唯一值派生出来的。即使你拥有我的整个数据库,除非你也有应用程序代码,否则你不会知道盐来自哪里。可能不是实际上增加安全性,因为仅仅加盐已经足够了(目前),但隐藏盐确实更安全。 - defines
良好的安全性建立在任何潜在攻击者都知道你的方法的假设上。这就是为什么我们使用“加密安全”哈希,而不是“加密模糊”的哈希。正如Jørn指出的那样,哈希的唯一(引用“仅仅”)附加安全性是为了打败彩虹表等。它们是加密安全哈希函数的补充。 - maxwellb

6
如果您首先使用MD5对密码进行加密,那么可以通过在数据库中重新生成哈希值来将所有MD5字符串转换为SHA1。检查密码也需要首先对其进行MD5加密,但我认为这不会产生太大影响。 php代码(登录):
之前: $login = (md5($password) == $storedMd5PasswordHash);
之后: $login = (sha1(md5($password)) == $storedSha1PasswordHash);
也适用于盐值加密,最初的想法来自这里

3

我认为你已经拥有了最好的选择。我更喜欢选项1而不是选项2,因为一旦设置SHA之后MD5就没有用处。

无法逆转MD5,因此您必须等待用户再次进行身份验证以创建新哈希。


2

不行 - 基本上在所有你关心的用户都被转换之前,你必须保持MD5不变。这就是哈希的本质 - 你没有足够的信息再次执行转换。

另一个符合其他选项的选择是使密码字段有效地自我描述,例如:

MD5:(md5 hash)
SHA:(sha hash)

您可以轻松地检测要使用哪个算法进行比较,并避免拥有两个字段。同样,您将在进行操作时用SHA覆盖MD5。

您需要进行初始更新以使所有当前密码声明为MD5。


4
哈希的大小使其自描述:MD5始终较小。 - Steven Sudit
2
长度不应该作为唯一的指标。您可能希望在使用相同的哈希算法将其全部切分时更改哈希中的内容(例如nonce计算,其他种子数据)。拥有单独的标识符可以告诉您正在使用哪个您的密码哈希方案。 - Rob
1
如果你的两种方法长度不同,那么你肯定可以使用长度作为指标。 - Vinko Vrsalovic
1
Rob,我同意在前面多加一个字节作为指示符是个好主意。方便的是,即使加上这个额外的字节,传统的MD5值仍然比新的MD5值要短。 - Steven Sudit

0

你的第二个建议听起来对我来说最好。这样,经常使用的用户将在未来拥有更安全的体验。

第一个建议有效地“quirks-mode”了你的代码库,只确保新用户拥有更好的SHA体验。


在我看来,这两个解决方案似乎是相同的,只是实现方式略有不同。无论哪种方式,你的密码在下次登录时都会被重新散列。 - Jørn Schou-Rode
无论哪种选择,下次用户登录时我都会替换现有用户的密码。问题只是如何让应用程序知道此后要使用哪个哈希值。 - Bruce Alderman

-1
如果MD5没有被加盐,你可以使用解密网站/彩虹表,例如:http://passcracking.com/index.php来获取密码。不过,使用重新编码方法可能更容易些。

5
如果可行的话,这样做并不是非常道德,除非你在破解密码时非常小心,确保不存储任何密码。 - Vinko Vrsalovic
3
无论你如何小心防止密码被存储或泄漏,某种原因让人感觉这是不道德的。 - Michael Burr

-4

在将密码转换为sha-1之前,您应该先知道真正的密码。

如果您想从md5加密字符串中找到真实的密码,可以尝试md5pass.com


3
在设计良好的系统中,这种情况绝不应该发生。所有密码都应该存储为加盐形式。 - William T Wild

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接