为什么不使用MD5进行密码哈希?

时间:2015-05-28 02:09:34

标签: security hash passwords md5 password-storage

我有一个白帽子黑客的朋友。他说md5并不是那么糟糕,实际上是非常安全的,只要我们正确使用它。

我相信他是对的。据我所知,有三种方法可以打破哈希:

  1. 使用彩虹桌(可以用长盐/随机盐保护)
  2. 碰撞(可通过多种盐或哈希来防止 - 如下例所示)
  3. 生成时间(如果我们为每个用户使用足够长的盐值,则不是很重要 - AFAIK)
  4. 我和我的朋友认为Blowfish并不是真的有需要,也可能是有害的,因为它可以减慢密码验证过程,并且它可以与DDOS攻击一起使用,即使使用较少的资源也可以分解服务器。

    所以,我想确保遵循算法真的安全吗?并且,是否有真正的理由选择Blowfish哈希算法?

    // return a 256 bit salt + 128 bit md5 binary hash value
    function hash(password, salt=null)
    {
        salt = (salt != null) ? salt : Random256BitBinaryValueGenerator();
        // What about using another user-specified parameter, like email address as salt?
    
        return salt + md5(salt + password) + md5(password + salt);
    
        // Or just use a non-cryptographic hash algorithm like crc32 to prevent collisions:
        // return salt + md5(salt + password) + crc32(salt + password);
    
        // Or even use two different salts:
        // return salt + md5(salt + password) + md5('C' + salt + password);
    }
    
    // check password
    function check(password, hash_value)
    {
        return hash(password, substring(hash_value, 0, 32)) == hash_value;
    }
    

3 个答案:

答案 0 :(得分:15)

MD5的collision resistance属性已经被打破了很长时间。请注意,preimage resistance和第二个原像抗性尚未被破解,但是因为有更好的算法(SHA-2),移动到这些算法是明智的,而不是依赖于已经开始的加密哈希失去其加密属性。注意:当存储散列密码时,碰撞阻力属性无关紧要< - 你需要确定的是,前映像电阻属性是合理的 - 在某些情况下找到原始密码在计算上是不可行的哈希值(和盐)。正如我所提到的,由于其中一个加密属性已被破坏,我担心其他人将很快跟进。

当您存储密码哈希时,您应该建立一些保护,以便在攻击者设法提取这些哈希值时无法检索原始密码。这很重要,因为如果攻击者设法检索密码表,那么他们就可以使用这些数据直接登录到您的系统,或者登录到用户重复使用相同密码的其他系统。

存储密码时,使用慢速算法非常重要,例如bcrypt,scrypt或pbkdf2。合法用户在首次登录时只需要经历一次延迟。攻击者必须经历他们猜测的每个密码的延迟 - 记住彩虹表将不会在这里使用,因为密码被腌制。攻击者将根据您选择的算法和迭代计数对每个密码进行散列扫描。

调整系统的迭代次数非常重要,因为正确的&#34;强度&#34;用于登录系统时不会给合法用户带来任何真正的烦恼。这被称为&#34;轮数&#34;或者#34;迭代计数&#34;。例如,迭代大约一秒应该就足够了。可以安全地假设攻击者可以以系统硬件速度的十倍速度运行哈希值。因此,这限制了攻击者每秒10次猜测,而不是MD5的20亿次。

关于DoS攻击

是的,您的应用程序在登录时执行的额外处理可能是攻击者向您的应用程序提交真正长密码的目标,或者是为了消耗服务器上的CPU和内存资源而反复使用登录请求命中它。 You are right to be concerned

可以通过以下方式减轻这些类型的攻击:

  • 记录每次登录尝试的用户名和IP地址。在说出6次尝试失败后,如果再次重复该用户名或IP,则会引起应用程序的响应延迟。这也有助于缓解一般的密码猜测攻击。
    • 例如,你可以人为地延迟1秒,然后是2秒,然后是4,直到合理的值(例如16秒)。
    • 这样做的好处是攻击者无法故意锁定另一个帐户,因为合法用户只需要等待16秒。
    • 攻击者可以使用僵尸网络和随机用户名来绕过这些检查,但是如果没有这种控制,他们需要大量的IP地址,而一个更随意的攻击者也不会意识到响应的延迟是人工。
  • 监控系统上的登录尝试次数。一旦超过设定的阈值速率(例如每秒10个),引入CAPTCHA以解决以继续登录过程。您选择的阈值速率在很大程度上取决于系统的用户群和容量。
  • 实施双因素身份验证。只有在验证一次性密码后才能通过散列验证密码。

答案 1 :(得分:5)

MD5的问题正是如此之快,您可以使用通用硬件计算9 Giga MD5/s。要用大约200000个单词来强制整个英语词典,你只需要几分之一毫秒。

这就是像BCrypt这样的适当哈希算法提供成本因素的原因。成本因子定义了计算哈希所需的时间,并且可以在将来添加。登录50毫秒并不是一个障碍,但对于暴力破解它是致命的。

答案 2 :(得分:0)

你说减慢验证是一个问题,但它是防止泄露哈希和蛮力攻击的唯一防御。现代解决方案重复散列值(即:数千次)只是为了提高计算成本。