security - 为什么不使用 MD5 进行密码散列?

标签 security hash passwords md5 password-storage

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

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

  • 使用彩虹表(可以通过长/随机盐保护)
  • 冲突(可以通过多个盐或哈希来防止 - 如下例所示)
  • 生成时间(如果我们为每个用户使用足够长的盐值,这并不重要 - AFAIK)

  • 我和我的 friend 认为 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;
    }
    

    最佳答案

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

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

    存储密码时,使用慢算法很重要,例如 bcrypt、scrypt 或 pbkdf2。合法用户在第一次登录时应该只需要经历一次延迟。攻击者将不得不经历他们猜测的每个密码的延迟 - 请记住,这里不会使用彩虹表,因为密码是加盐的。攻击者将根据您选择的算法和迭代次数对每个密码猜测进行哈希处理。

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

    关于 DoS 攻击

    是的,您的应用程序在登录前执行的额外处理可能是攻击者向您的应用程序提交非常长的密码,或者通过登录请求反复访问它以消耗服务器上的 CPU 和内存资源的目标。 You are right to be concerned .

    可以通过以下方式缓解这些类型的攻击:

  • 记录每次登录尝试的用户名和 IP 地址。在说 6 次尝试失败后,如果该用户名或 IP 再次重复,则在您的应用程序的响应中引入延迟。这也将有助于减轻一般的密码猜测攻击。
  • 例如,您可以人为地延迟 1 秒,然后是 2 秒,然后是 4 秒,直至达到合理的值(例如 16 秒)。
  • 这样做的好处是攻击者无法故意锁定另一个帐户,因为合法用户只需等待 16 秒。
  • 攻击者可以使用僵尸网络和随机用户名来绕过这些检查,但是与没有这种控制的情况相比,他们需要大量的 IP 地址,而且更随意的攻击者也不会意识到响应延迟是人为的。
  • 监控系统上的登录尝试次数。一旦超过设定的阈值速率(例如每秒 10 次),请引入验证码来解决以继续登录过程。您选择的阈值速率很大程度上取决于您的系统的用户群和容量。
  • 实现两因素身份验证。一旦一次性密码得到验证,仅通过散列来验证密码。
  • 关于security - 为什么不使用 MD5 进行密码散列?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30496061/

    相关文章:

    ruby-on-rails - 在与 Gmail 通信时,ActionMailer 的 "enable_starttls_auto"设置是否保护我的电子邮件凭据?

    sqlite - 如何确定SQLite数据库没有被修改?

    python - 是否可以在 Python 3 中将类用作字典键?

    perl - 如何将 boolean 条件结果分配给 perl 中的标量变量?

    hash - 强制使用复杂密码 "more important"比加盐好吗?

    database - 存储原始密码文本

    Java EE 应用程序服务器和 Perl 脚本

    javascript - Paypal 快速结帐。在 onAuthorize 函数中将数据存储在 DB 中是否安全?

    algorithm - 需要帮助提出哈希函数算法

    passwords - 将正则表达式添加到 Sitecore 8 中的密码复杂性