如何持续保持与本年度硬件相关的bcrypt轮数?

时间:2013-03-27 15:28:09

标签: php security passwords bcrypt

我看到建议将轮数设置为($currentYear - 2000)以考虑摩尔定律,因此2013年将是13轮,因此2^13总迭代次数。当然,你需要考虑你自己的硬件,以确保它不会花太长时间(我看到1 second被推荐为“安全”用于检查密码/哈希,并且13轮在我当前的那个标记附近硬件)。

对于社交网络类型的网站,这听起来合理吗?或者,我将使用($currentYear - 2000)为将来的密码检查速度非常慢做好准备?

另外,你如何处理从一年到下一年的轮数变更?不会改变轮数改变哈希值,因此不允许你在2014年检查哈希,因为支票将使用额外一轮?您是否必须每年重新计算每一个哈希值,或者它将如何正常工作?

3 个答案:

答案 0 :(得分:16)

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

话虽如此,我也质疑大多数用法的1秒建议。如果你正在处理高度敏感的信息,1秒(或者更长)是可以的。但对于普通网站,我通常建议0.25到0.5秒。在某些情况下,你可以降低,但我不会没有充分的理由。

现在,问题本身。使用crypt()password_hash()时,迭代计数以返回哈希格式存储。事实上,盐也是如此。因此,计算哈希所需的所有信息都包含在其中!

如果您没有使用这些API中的任何一个(或我维护的polyfill:password-compat),那么我真的不得不想知道为什么你不是。不要发明自己的密码加密。不要使用使用本机哈希(如phpass)的库,除非您有充分的理由(出于某些政府合规性原因,或与PHP的兼容性<= 5.2)。

通常认为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 for password_hash()以获取更多相关信息(我从大量来源收集数据,并在RFC中包含参考文献)。

编辑 - 跟进@ AnotherParker的评论:

  

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

排序正确。嗯,是的,但是忽略了我上面谈论的内容。

哈希函数的成本参数是时间 - 权衡权衡。您需要花些时间为每个哈希添加额外的工作量。在相同的硬件上,花更多的时间会产生更多的工作。产生更多工作的另一种方法是获得更快的硬件。

但建议是测试当前硬件上的哈希函数,并使其合理地制作它。如果0.5秒是您今天可以承受的最大值,除非您升级服务器硬件,如何增加成本来帮助您?简而言之,它不会,因为你将打破你已经确定的最重要的时间限制。

所以除非你已经产生了弱哈希,否则你不能在不增加服务器功能的情况下增加工作参数。

另外,请查看this answer on the subject

答案 1 :(得分:5)

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

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

会产生类似

的内容
$2a$04$thisshallbemysalt.rAnd0ml0ok1ngch4rsh3re
在第一个$符号代表bcrypt algorithem之后

2a,而下一个04代表轮数 - 所以通过查看哈希,你可以看到完成创建它的轮次数。

因此,当您决定是时候提高轮数时,您可以检查用户登录时生成存储哈希时使用的轮次数 - 如果不是您当前的轮数,则重新哈希他们的轮次然后将密码保存为新哈希(之后检查其密码是否与现有哈希匹配;当然; - )

答案 2 :(得分:4)

key stretching的想法是强制执行无法执行,因为计算哈希数百或数千次,每轮,攻击者系统上的额外时间相同。

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

例如,如果使用SHA256哈希,系统每秒可以执行X(比如1,000,000)哈希。通过按键拉伸(并因此进行散列,例如500次),您可以将此系统的每个密码降至1,000,000 / 500 = 2,000次/秒。你有效地将攻击者放慢了500倍。如果你使用750轮你......确切地说!使攻击者减速750倍。但是增加轮次数会影响你的系统/网站/应用程序,所以你不想太高高“只是为了确定”;用户会抱怨登录速度慢!

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

当你提升回合次数为CBroe explains时。

我不知道是谁想出了2 ($ currentYear - 2000)的推荐(我很想看到来源!没关系,{{3但是如果你问我这是全牛。我建议您found it更密切,并检查read the answers

如果你的bcrypt需要.2到.5秒(如果你问我,这是一个可接受的“延迟”,这意味着攻击者可以使用相同的硬件和每秒蛮力约5到2个哈希值如果他/她可能投入5,000 / 2,000或5,000,000 / 2,000,000。在可接受的时间(甚至是生命周期)内对整个160bit(SHA1),256bit(SHA256)甚至448bit(bcrypt)空间进行暴力破坏仍然是不可行的。