很多哈希迭代:每次都附加盐值吗?

38

我长期使用未加盐的md5 / sha1,但由于这种方法并不真正安全(随着时间的推移越来越不安全),因此我决定切换到加盐的sha512。此外,我想通过使用多次迭代(例如100次)来减慢哈希值的生成速度。

我的问题是,我应该在每次迭代中都添加盐还是仅在开头添加一次。以下是两种可能的代码:

每次都追加:

// some nice big salt
$salt = hash($algorithm, $salt);

// apply $algorithm $runs times for slowdown
while ($runs--) {
    $string = hash($algorithm, $string . $salt, $raw);
}

return $string;

仅追加一次:

// add some nice big salt
$string .= hash($algorithm, $salt);

// apply $algorithm $runs times for slowdown
while ($runs--) {
    $string = hash($algorithm, $string, $raw);
}

return $string;

我最初想使用第二个版本(只追加一次),但后来发现有些脚本每次都会追加盐。

所以,我想知道每次添加盐是否会增加哈希的强度。例如,攻击者是否可能找到一种聪明的方法来创建一个100timesSha512函数,其速度比仅执行sha512 100次要快得多?

5个回答

51
简而言之:是的。请使用第一个示例……如果反馈回原始数据时没有添加原始数据,哈希函数可能会丢失熵(我现在找不到参考资料,我会继续寻找)。
就记录而言,我支持多次哈希。
生成需要500毫秒的哈希值对于您的服务器来说并不太慢(考虑到生成哈希值通常不是绝大多数请求所做的)。但是,需要那么长时间的哈希将显着增加生成彩虹表所需的时间……
是的,它确实暴露了DOS漏洞,但它也可以防止暴力攻击(或者至少使它们变得极其缓慢)。这绝对是一种权衡,但对于某些人来说,好处超过了风险…
整个过程的参考资料(更像是概述):密钥强化 至于退化碰撞,我目前找到的唯一来源是 这个讨论……
关于此主题的更多讨论:
  1. HEKS提案
  2. SecurityFocus关于哈希的博客
  3. 有关Oracle密码哈希算法的论文
还有几个链接:
  1. WikiPedia上的PBKDF2
  2. PBKDF2标准
  • 适用的电子邮件线程
  • 单纯的哈希远远不够
  • 有大量的结果。如果你想要更多信息,请谷歌搜索“哈希伸展”...那里有大量的好信息...


    +1 不明白为什么这个被踩了。如果您能找到那个参考资料,我会非常感激的 ;) - NikiC
    对于DoS漏洞,我仍然认为你的建议是错误的。+1 - rook
    1
    @The Rook:考虑到我阅读过的大多数来自值得信赖研究人员的安全论文都建议在使用密钥之前进行密钥拉伸(无论是用于存储还是加密)。而且考虑到你需要进行PCI合规性的拉伸,我不确定这是一个错误的建议…… - ircmaxell
    @ircmaxell 我不同意,我认为尝试两次就是浪费,而100次仍然意味着字典密码在不到一个小时内被破解。(我仍然给你一个+1,只是我不认为它适用于Web应用程序。) - rook
    6
    @nikic说的是从暴力攻击的角度来看(减缓攻击者的速度)。我说的是从碰撞的角度来看。MD5(MD5(data))将包含所有MD5(data)的碰撞。这种降级是线性的,所以不是一个重要的问题,但已足以导致PBKDF2被引入来解决这个问题(考虑到这是PBKDF1PBKDF2之间的主要差异)。 - ircmaxell
    显示剩余8条评论

    6
    除了多次重新散列外,我建议每个密码/用户使用不同的盐。尽管我认为5000次迭代有点太多了,可以尝试更低的数字。这里有一个权衡;您需要根据自己的需求和硬件进行调整。
    对于每个密码使用不同的盐,攻击者将被迫逐个暴力破解每个密码,而不是构造彩虹表,这会大大增加工作量。
    像往常一样,这里是一个推荐阅读:仅仅散列还远远不够 编辑:迭代散列是一种完全有效的策略。存在权衡,但所有事情都有它们的权衡。如果您担心计算时间,为什么不只存储明文密码呢?

    嗨,各位,这里发生了什么事情? - user1228

    3
    请不要自己编写加密算法。这就是 OpenSSL 等库存在的意义。以下是使用 OpenSSL 制作盐哈希的几个很好的示例。
    《OpenSSL 中的盐哈希》(Salted Hashes in OpenSSL)。

    使用OpenSSL创建哈希值几乎是最不可移植的方式。你很少能从PHP中获得命令行访问权限,而且看起来你需要它。此外,我不明白为什么我不能“自己编写加密算法”。我只是假设a) sha512比sha1更好,b) 加盐是好的,c) 拉伸是好的。因此,我通过三种不同的方式改进了我的原始sha1方法,我不明白为什么这会是坏事。 - NikiC
    1
    使用非常流行的标准库怎么会不可移植呢?不需要访问命令行,因为基本的加密功能通常都包含在任何语言所需的函数调用中。我并不是说要盲目地从链接中复制粘贴命令,我是说这种做法已经被正确地实现过,因此没有必要再错误地重新发明轮子。 - Marcin

    0
    迭代哈希的原因是使过程尽可能缓慢。因此,您可以做得更好:为每个迭代使用不同的盐。这可以通过使用固定密钥对原始数据进行一遍又一遍的加密,并与盐值进行异或运算来完成。

    你能提供一下为什么使用多个盐值会更好的参考资料吗? - NikiC
    实际上在学术论文中并没有这样的内容。这只是迫使攻击者在每个周期上进行一次额外的加密,并使任何哈希预计算变得不可能,因为根本没有重复的数据。 - blaze
    唯一的盐值并不能使预计算变得不可能,它只是限制了生成彩虹表破解单个哈希的有用性。 - Igorio
    我的意思是部分预计算哈希函数本身:在开头进行初始化和常见数据块。保存这个状态,你可以在每次操作中节省一点时间。 - blaze

    0

    我更喜欢使用双重sha1加上两种不同的盐,并通过每次无效密码检查时递增地延迟答案(使用简单的usleep)来防止DoS攻击。


    1
    我认为使用usleep会使您的应用程序易受DoS攻击。PHP是一种同步、阻塞语言,因此睡眠仍然会阻塞PHP进程。这样,您可以通过比不使用睡眠更少的连接使服务器无响应 ;) - NikiC
    1
    它不仅会阻止PHP的最大并行执行,还会阻止Web服务器处理的最大并行请求(例如Slowloris;缓慢的请求会导致Apache Web服务器崩溃等)。相反,usleep有助于防范暴力登录攻击,但甚至会增加DoS攻击的有效性。 - Kissaki

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