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

Posted

技术标签:

【中文标题】如何将密码哈希从 MD5 转换为 SHA?【英文标题】:How do I convert password hashing from MD5 to SHA? 【发布时间】:2010-11-25 18:29:53 【问题描述】:

我有一个旧应用程序,它的用户密码使用 MD5 哈希存储在数据库中。我想用 SHA-2 系列中的东西替换它。

我已经想到了两种可能的方法来实现这一点,但都显得相当笨拙。

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

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

在任何一种情况下,对于不经常登录的任何用户,MD5 身份验证都必须保留一段时间。并且任何不再活跃的用户将永远不会切换到 SHA。

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

【问题讨论】:

你的两个解决方案在我看来都不错。 我正在支持 Ned 的回答,他的观点很好。 对于从未切换的用户 - 我会考虑在一定比例的人切换并且经过足够的时间以摆脱 MD5 哈希之后。在此期间未登录的人在再次登录时必须重置密码。这是否(以及何时)可以接受是一个商业决策。 我想知道你是否真的需要一个额外的标志:旧哈希的长度更短。 声明显而易见:不要忘记在验证后重新加密密码 :-) 【参考方案1】:

基本相同,但可能比添加额外字段更优雅:在Django 的默认身份验证框架中,密码哈希存储为如下构造的字符串:

hashtype$salt$hash

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

sha1$a1976$a36cc8cbf81742a8fb52e221aaeab48ed7f58ab4

【讨论】:

唯一的问题是它存储盐的方式使其明显是盐,而不是为用户使用另一个唯一或派生的值(例如时间戳的变异版本他们的帐户创建,或位翻转他们的用户名等)。有争议的是,这是否会对破解所需的时间产生任何目前可行的差异,我只是偏执。 @Dustin:这里的额外优势是每次用户更改密码时都可以更改盐。 但是你正在储存盐。如果我有你的数据库和你所有的哈希值,我也有你的盐。 @Dustin:在这个设置中,salt 只是用来使使用rainbow tables 的攻击无效,因为每个用户的salt 会有所不同。 是的,我了解其中的好处,我只是说我个人不喜欢储存盐,因此它显然是盐。正如我之前所说,知道盐并不一定会使破解密码变得更加可行,但我很偏执。我使用对每个用户都不同的盐,但它源自用户独有的另一个值。即使您拥有我的整个数据库,除非您还拥有应用程序代码,否则您不会知道盐的来源。可能不会实际增加安全性,因为单独加盐就足够了(目前),但隐藏盐更安全。【参考方案2】:

如果您通过首先对它们进行 MD5 处理来创建未来的密码,则可以通过在数据库中重新散列它们来将所有 MD5 字符串转换为 SHA1。检查密码也需要先对它们进行 MD5 处理,但我认为这不是什么大问题。

php-code(登录):

上一页: $login = (md5($password) == $storedMd5PasswordHash);

之后: $login = (sha1(md5($password)) == $storedSha1PasswordHash);

也适用于盐渍,最初的想法来自here。

【讨论】:

【参考方案3】:

我认为您已经拥有了最好的可能性。我更喜欢 #1 而不是 #2,因为一旦设置了 sha,md5 就没有用了。

没有办法反转MD5,所以你必须等待用户再次认证才能创建新的哈希。

【讨论】:

【参考方案4】:

不 - 基本上,您必须保留 MD5,直到您关心的所有用户都已转换。这就是散列的本质 - 您没有足够的信息来再次执行转换。

与其他选项保持一致的另一个选项是使密码字段有效地自我描述,例如

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

然后,您可以轻松检测用于比较的算法,并避免使用两个字段。同样,您将在进行过程中使用 SHA 覆盖 MD5。

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

【讨论】:

散列的大小使其具有自描述性:MD5 总是更小。 长度不应作为唯一指标。您可能希望更改散列中的内容(例如随机数计算、其他种子数据),同时使用相同的散列算法将其全部切碎。拥有一个单独的标识符会向您​​表明正在使用哪个您的密码哈希方案。 如果您只有两种方法的长度不同,那么您当然可以使用长度作为指标。 Rob,我同意在前面有一个额外的字节左右作为指标是个好主意。方便的是,旧版 MD5 值甚至比带有额外字节的 MD5 短。【参考方案5】:

你的第二个建议对我来说是最好的。这样,频繁使用的用户在未来将获得更安全的体验。

第一个有效的“怪癖模式”是您的代码库,仅确保新用户拥有更好的 SHA 体验。

【讨论】:

对我来说,这两种解决方案似乎是相同的,只是实现方式略有不同。无论哪种方式,您的密码都会在您下次登录时重新散列。 在任何一个选项中,我都会在现有用户下次登录时替换他们的密码。这只是如何让应用知道之后使用哪个哈希的问题。【参考方案6】:

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

【讨论】:

如果可行,这不是很道德,除非您在破解密码时非常小心,不要存储任何密码。 @Vinko - 出于某种原因,即使您注意防止密码被存储/泄露,也会感觉不道德。【参考方案7】:

是的,您应该先知道真实密码,然后再将其转换为 sha-1..

如果你想从md5加密字符串中找到真​​正的密码,可以试试md5pass.com

【讨论】:

这在设计良好的系统中永远不可能。所有密码都应加盐存储。

以上是关于如何将密码哈希从 MD5 转换为 SHA?的主要内容,如果未能解决你的问题,请参考以下文章

哈希密码,从破碎的方法到现在最安全

如何在 Java 中使用 SHA-512 对密码进行哈希处理?

认识区块链——哈希算法

将密码转换为哈希 PHP

openssl evp 哈希算法(md5,sha1,sha256)

加密方式区别