5

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

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

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

我和我的朋友认为 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;
}
4

3 回答 3

16

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

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

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

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

关于 DoS 攻击

是的,您的应用程序在登录之前执行的额外处理可能成为攻击者向您的应用程序提交非常长的密码或反复使用登录请求攻击它以消耗服务器上的 CPU 和内存资源的目标。你担心是对的

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

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

MD5 的问题恰恰在于它太快了,用普通硬件可以计算出大约9 Giga MD5/s 。要强行使用大约 200000 个单词的整个英语词典,您只需要几分之一毫秒。

这就是为什么像 BCrypt 这样的适当哈希算法会提供成本因素的原因。成本因素定义了计算哈希需要多少时间,并且可以在未来增加。50 毫秒的登录时间几乎不是障碍,但对于暴力破解来说却是致命的。

于 2015-05-28T09:23:30.800 回答
0

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

于 2015-05-28T03:57:39.373 回答