为什么人们认为这是散列密码的不好方法?

信息安全 密码学 密码 哈希
2021-08-13 17:41:47

这段代码有什么问题?

$password = "hello";
$password = md5($password);
for ($i = 1; $i < 20; $i++) {
  $password = md5($password);
}

我认为有权访问哈希存储的攻击者无法使用超过 2 个字符来解密任何密码。

攻击者必须解密这个哈希列表才能获得明文密码。

69a329523ce1ec88bf63061863d9cb14
0dcd649d4ef5f787e39ddf48d8e625a5
5d6aaee903365197ede6f325eb3716c5
cbe8d0c48ab0ed8d23eacb1621f6c5c3
8fa852c5f5b1d0d6b1cb0fad32596c71
91a84cf929b73800d2ff81da28834c64
45b7d5e4d3fca6a4868d46a941076b72
e5b7d9d10fef132829731255ef644319
b3af6ff5f5c7ae757ca816a6cb62f092
150f3682b2e58d1d0e1f789f9ba06982
3f76626950bf31dbc815c667ca4b2b43
44f4c75517671e12946aab3c8c293f98
442256b098b2d88e93428b08b5155308
7fd8ebc5bdff94f24a10decaa1ab64e8
d04bbc863839b720d932a697f0bf443b
de737c934db23c2d1d1026863e7583a8
d745f6394700c4ab1e9ded0924ea35d2
ce9428b51d3a63431c57a435423877b6
7017f40bdb4f1be1f5fae7dd0fc7b907

使用蛮力,attacher 应该尝试 36 32 (*19) 组合,这是非常无法实现的。这不是真的吗?

4个回答

您的方法中的错误是:

  • 您使用的迭代次数太少(20 太低,应该是 20000 或更多):密码处理仍然太快,具有基本 PC 的攻击者仍然能够每秒“尝试”数千万个密码。
  • 没有盐:攻击者可以以非常低的每个密码成本攻击多个密码,例如使用预先计算的散列密码表(特别是彩虹表)。
  • 您正在发明自己的密码学。好奇并试图理解事物并没有错,但是由于没有确定的测试可以知道给定算法是否安全,因此发明自己的密码学通常是灾难的根源。不要这样做。

你应该做的是使用bcryptPortable PHP 密码散列框架中有一个 PHP 实现

其他人已经描述了这种散列方法的局限性;我想指出问题中的一个概念错误:

我认为使用我的数据库的攻击者无法解密任何长度 > 2 的密码

攻击者必须解密这个 md5 哈希列表才能获得普通密码:

[中间结果列表]

这里的错误是认为中间结果的复杂性提供了针对暴力字典攻击的任何保护。我认为提问者认为攻击必须从存储的哈希开始向后工作,并依次暴力破解每个中间结果。

这根本不是真的。合理的字典攻击将从可能的密码开始,一次攻击整个 20 哈希堆栈。这是算法草图:

for each candidate password:
    hash 20 times
    compare with stored hash

使用它来检查所有可能的 3 字符密码(假设可打印 ASCII)只需要 20 * 95^3 = 17147500 哈希,这基本上是微不足道的。尽管有更大的中间值,但使用 SHA-512 代替 MD5 会更安全,只是因为每个散列需要更长的时间来计算。

tl; dr 如果密码本身没有足够的熵,复杂的散列函数将无法拯救您。

20x MD5 是一种快速散列算法,这意味着它可以以惊人的速度生成密码。

请停止使用快速哈希算法来存储密码。即使是单独的盐;如果有人可以直接(阅读:离线)访问您的数据库,则可以很容易地计算出他们。

这篇文章解释了为什么比我做得更好:

http://codahale.com/how-to-safely-store-a-password/

这篇文章大量提到了 BCrypt(带有 PHP 库的链接),但请记住,还有其他慢速散列算法可能适合您。

问题是这是一个非常明显的“算法”,而且启动速度非常快。
很可能有一个预计算的彩虹表可用于这个“算法”,即使没有,md5 也足够快,能够在实际时间内预计算一个。

您应该始终为每个密码使用单独的盐以避免这种攻击。