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

Security 为什么不使用MD5进行密码哈希?,security,hash,passwords,md5,password-storage,Security,Hash,Passwords,Md5,Password Storage,我有一个朋友是白帽黑客。他说,md5并没有那么糟糕,而且实际上是非常安全的,只要我们正确地使用它 我相信他是对的。据我所知,有3种方法可以打破散列: 使用彩虹表(可通过长/随机盐保护) 冲突(可以通过多个盐或散列来防止-如下面的示例所示) 生成时间(如果我们为每个用户使用足够长的salt值-AFAIK,则生成时间并不重要) 我和我的朋友认为,河豚并不是真正需要的,它也可能是有害的,因为它会减慢密码验证过程,并且它可以与DDOS攻击一起使用,即使使用更少的攻击资源也可以破坏服务器 所以,我想确定下

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

我相信他是对的。据我所知,有3种方法可以打破散列:

  • 使用彩虹表(可通过长/随机盐保护)
  • 冲突(可以通过多个盐或散列来防止-如下面的示例所示)
  • 生成时间(如果我们为每个用户使用足够长的salt值-AFAIK,则生成时间并不重要)
  • 我和我的朋友认为,河豚并不是真正需要的,它也可能是有害的,因为它会减慢密码验证过程,并且它可以与DDOS攻击一起使用,即使使用更少的攻击资源也可以破坏服务器

    所以,我想确定下面的算法是否真的安全?还有,是否真的有理由使用河豚哈希算法

    // 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;
    }
    

    您将减慢验证速度视为一个问题,但这是针对泄露的哈希和暴力攻击的唯一防御措施。现代解决方案反复散列值(即:数千次),只是为了提高计算成本

    MD5的问题恰恰在于它太快了,你可以用普通硬件计算大约。你只需要几分之一毫秒的时间就可以粗暴地使用一本大约20万单词的整本英语词典

    这就是为什么像BCrypt这样合适的散列算法提供了一个成本因素。成本因素定义了计算散列所需的时间以及将来可以减少的时间。50毫秒的登录时间很难算是一个障碍,但对于暴力强迫来说却是致命的。

    MD5的属性已经被破坏了很长一段时间。请注意,第二个和第二个前映像的阻力尚未被破解,然而,由于有更好的算法(SHA-2),因此明智的做法是转向这些算法,而不是依赖已经开始失去其加密属性的加密散列。注意:在存储散列密码时,抗冲突属性并不重要—您需要确保前映像抗冲突属性是可靠的—在给定特定散列值(和salt)的情况下,在计算上不可能找到原始密码。正如我提到的,由于其中一个加密属性已经被破坏,我担心其他属性很快就会被破坏

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

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

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

    关于拒绝服务攻击 是的,您的应用程序在登录前执行的额外处理可能成为攻击者的目标,攻击者可以向您的应用程序提交很长的密码,或者通过登录请求反复攻击应用程序,以消耗服务器上的CPU和内存资源

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

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

    我知道SHA2是安全的,或者说河豚更安全,但我想知道使用这些新算法的真正原因,我的意思是,如果我们可以使md5安全,为什么要使用其他算法?根据下面的链接,仅仅两个散列意外碰撞的概率是(1/2)^128,所以md5(s+p)+md5(p+s)碰撞的概率是(1/2)^256,这在我看来是非常安全的,即使对于需要安全性的应用程序,当与随机salt组合时也是如此。另外,正如我所知,由于哈希输出的长度是固定的,所以没有一个无冲突的算法,所以,如果我们没有找到一个