如何持续保持与当年硬件相关的bcrypt回合数量?

我看到一个建议,轮数设置为($currentYear - 2000)来解释摩尔定律,因此2013年将是13轮,因此总共需要2^13次迭代。 当然,你需要考虑你自己的硬件,以确保它不会花太长时间(我看到推荐1 second作为检查密码/散列的“安全”,并且在我目前的硬件上有13个回合落在该标记周围)。

这对于社交网站类型的网站是否合理? 或者我会在未来通过使用($currentYear - 2000)为自己设置非常慢的密码检查?

另外,你如何处理从一年到下一年改变回合数? 不会改变轮次数改变哈希,因此不允许您在2014年检查2013年的哈希,因为该检查会使用额外轮次? 你会不会每年重新计算每一个散列,或者它会如何工作?


首先,我质疑该建议(根据年份调整成本)。 成本应该基于硬件的速度,而不是当前的日期。 如果您从现在到2015年之间不升级服务器,则没有理由增加成本。 你所做的只是缓慢的过程。

有了这个说法,我也质疑大多数用法1秒的建议。 如果你处理的是高度敏感的信息,那么1秒(或者更长)就可以。 但对于普通网站,我通常建议在0.25到0.5秒之间。 在某些情况下,你可以降低,但我没有强有力的理由。

现在,问题本身。 当您使用crypt()password_hash() ,迭代计数将以返回散列格式存储。 事实上,盐也是如此。 所以计算散列所需的所有信息都包含在内!

如果你没有使用这些API(或者我所维护的polyfill:password-compat),那么我真的不知道你为什么不这样做。 不要发明自己的密码加密。 除非您有充分的理由(出于某些政府法规遵从性原因或与PHP <= 5.2兼容),否则不要使用使用本机散列的库(如phpass)。

通常认为bcrypt是当今最强大的散列格式。 SCrypt更强大,但是它存在一些问题,并且它仍然是非常新的(并且它在PHP内核中尚未提供)。 所以只需使用bcrypt ...

password_hash() API有一个机制让你做你想问的问题: password_needs_rehash() 。 基本上,你传递了散列和你今天使用的选项,它告诉你是否需要重新散列它:

if (password_verify($password, $hash)) {
    if (password_needs_rehash($hash, PASSWORD_BCRYPT, ['cost' => 14])) {
        $hash = password_hash($password);
        update_password_in_database($hash);
    }
    $loggedin = true;
}

阅读RFC的password_hash()以获取更多信息(我从大量来源收集数据,并在RFC中包含了参考)。

编辑 - 跟进到@ AnotherParker的评论:

犯罪分子不会因为没有升级服务器而停止升级他们的破解盒。 您需要随着时间的推移增加工作参数以阻止脱机攻击。

分类为真。 嗯,是真的,但错过了我上面谈论的内容。

散列函数的成本参数是一个时间 - 成本折衷。 你花费一些时间来为每个散列添加额外的努力。 在同一个硬件上,花更多的时间会产生更多的工作。 另一种产生更多工作的方式是获得更快的硬件。

但是,建议您在当前的硬件上测试散列函数,并尽可能使其成本合理。 如果0.5秒是您今天能够承受的最大值,除非您升级服务器硬件,那么增加成本对您有什么帮助? 总之,这不会因为你打破已经确定的最大时限非常重要。

所以,除非你已经产生了弱哈希值,否则你不能增加工作参数而不增加服务器的能力。

另外,请检查这个问题的答案


当您使用bcrypt时,轮次数是生成的哈希的一部分:

crypt ( 'Password', '$2a$04$thisshallbemysalt' );

会导致类似的情况

$2a$04$thisshallbemysalt.rAnd0ml0ok1ngch4rsh3re

2a在第一个$符号代表bcrypt算法后,接下来的04代表回合数 - 所以通过查看哈希值,您可以看到创建它的次数。

因此,当您决定是时候增加轮次数时,您可以检查用户登录时用于生成已存储哈希的回合数 - 如果它不是您当前的回合数,则会在那里重新输入其密码并且然后,并将其保存为新的散列(在检查其密码是否与现有的散列匹配后,当然;-))


关键扩展的想法是让蛮力不可行,因为对于每一轮来说,在攻击者的系统上花费相同数量的额外时间计算哈希数百次或数千次。

如果需要1秒或0.9秒或2.5秒,这并不重要。 这个想法是,每秒蛮力数百万密码哈希是不可行的。 这是重要的因素,而不是实际轮数。

例如,如果使用SHA256散列,系统可以每秒处理X(例如1,000,000)散列。 通过密钥扩展(并因此散列,例如500次),您可以将该系统的密码降至每秒1,000,000 / 500 = 2,000次。 你有效地减缓了攻击者500倍。如果你使用750轮,​​你......完全! 将攻击者减慢750倍。但增加轮次数量也会影响您的系统/网站/应用程序,因此您不想过高以“确保”; 用户会抱怨登录缓慢!

这源于例如SHA1 / 256/512,MD4 / 5等针对速度而优化的事实。 而你想要的是速度优化的算法,所以你可以减缓攻击者的速度。 因此,每隔几年你就可以简单地增加轮次数,因为你的用户的登录时间仍然可以接受,但是它会减缓攻击者的速度,使得不值得尝试强制哈希(或者例如最少强迫他们专注于少量帐户而不是所有帐户)。

当你按照CBroe解释的那样重复轮次时。

我不知道是谁提出了2($ currentYear - 2000)的建议(我很想看到一个消息来源!Nevermind,找到了它),但是如果你问我这是完全公牛。 我建议你仔细阅读答案,并检查这个问题/答案。

如果你的bcrypt需要0.2秒到5秒(如果你问我的话,这是一个可以接受的'延迟'),这意味着攻击者可以在相同的硬件的情况下每秒蛮力约5到2次哈希,如果他/她可能会投资5,000 / 2,000或5,000,000 / 2,000,000。 在可接受的时间(甚至是生命周期)内,对整个160位(SHA1),256位(SHA256)甚至448位(bcrypt)空间进行暴力破解仍然是不可行的。

链接地址: http://www.djcxy.com/p/28931.html

上一篇: How to continuously keep the number of bcrypt rounds relevant to the current year's hardware?

下一篇: Storing bcrypt hashes