现在(2012年7月)建议的用于对普通网站散列密码(仅存储名称,电子邮件地址和家庭住址,而不存储信用卡或医疗信息)的bcrypt回合次数是多少? ,bcrypt密码破解社区的当前功能是什么?一些bcrypt库使用12轮(2 ^ 12次迭代)作为默认设置。那是推荐的工作因素吗? 6个回合不够强(这恰好是Javascript中客户端bcrypt哈希的限制,另请参阅挑战性挑战:客户端密码哈希和服务器端密码验证)?

我已阅读答案https://security.stackexchange.com/a/3993/11197,其中深入讨论了如何平衡各种因素(尽管适用于PBKDF2-SHA256)。但是,我正在寻找一个实际的数字。经验法则。

评论

我做120.000,但这取决于您的应用程序。它仅取决于您的应用程序以及您可以在其上花费的CPU能力。例如。如果您每秒有1个用户登录并且仅使用2个内核,那么我认为您的操作次数不会超过10.000。基本上,您需要使用“时间”命令检查所需的时间,然后亲自查看。接近秒的东西应该可以。

@Andrew:我自己系统的速度不应领先于迭代次数。暴力破解者的当前速度应该决定多少次迭代被视为安全的。因此,我的问题是:当今认为有多少次迭代是安全的?

@JasonSmith,您的系统的速度很重要,因为它决定了您可以合理地进行多少次迭代而不会造成系统崩溃。您需要尽可能多的迭代,因为现实是没有足够的迭代次数可以完全保证安全:我们只是在某种程度上降低风险,而没有消除风险。没有足够大的轮数可以被认为是安全的。如果您在此处提出问题,请准备好听取您的答案。

@ D.W。写道:“请准备好听取您的答案”,如果我给人的印象是强或固执,那是对不起。也许作为非英语母语者,我的评论传达了错误的信息。我非常感谢所有答案,并努力理解其背后的理由。

在StackOverflow上重复:最佳bcrypt工作因子

#1 楼

我认为您所有问题的答案已经包含在Thomas Pornin的答案中。您已链接到它,因此大概了解了它,但是我建议您再次阅读它。

基本原理是:不要选择多轮;相反,请选择密码验证将在您的服务器上花费的时间,然后根据该时间计算轮数。您希望验证能花费的时间尽可能长。他建议合理的目标是使密码验证/散列每个密码花费241毫秒。 (注意:Thomas最初写的是“ 8毫秒”,这是错误的-这是耐心的一天而不是一个月的数字。)这仍然可以让您的服务器每秒验证4个密码(如果可以,请输入更多密码)平行)。托马斯估计,如果这是您的目标,那么大约20,000发子弹就在正确的范围内。理想情况下,您可以确定处理器需要花费多长时间,然后相应地选择数字。这并不需要很长时间。因此,为了获得最佳结果,只需整理一下脚本并计算出需要进行几轮操作,以确保密码散列在您的服务器上花费约240毫秒(或更长的时间,如果可以承受的话)。

评论


时间无所谓,金钱就是世界旋转的原因。

–rook
2012年7月15日在23:39



附言我不建议在Javascript中实现bcrypt,因为性能可能会很差。我假设您正在服务器上计算bcrypt。 (我认为在客户端上计算bcrypt没有足够的价值,因此我不建议在客户端上计算bcrypt。)我建议使用bcrypt的本机优化实现。它将运行得更快。

– D.W.
2012年7月16日17:49



@David天宇Wong,我们的系统可以承受的转数是相关的。没有实用的轮数足以使NSA无法破解任何密码(甚至是弱密码)。因此,您永远无法获得100%的安全性–在您为自己制作的难度有多大与为对手制作的难度有多高之间始终是一个折衷。但是考虑到用户如何选择密码的现实,我们永远无法像对手所希望的那样使密码变得如此困难。这是减轻风险,而不是消除风险。

– D.W.
2015年2月7日在20:52

@David天宇Wong,很多人选择一个弱密码(例如,10位熵)。例如,我们需要进行2 ^ 70次迭代才能使其相对于NSA更加安全。如果您对bcrypt进行了2 ^ 70次迭代,那么实际上没有人可以使用它,因为对于好家伙来说,它太慢了。这就是为什么我说迭代次数没有任何价值,既可以提供强大的安全性来抵御强大的对手(例如NSA),又可以使系统的合法用户使用得足够小。无论如何,我们离提出的问题有点遥远。

– D.W.
2015年2月8日,下午1:21

@David天宇Wong,具有10位熵的密码是正常的。但是,如果您不喜欢这种密码,请考虑使用20位熵的密码。 (超过一半的用户使用的密码的熵少于20位。)然后,您将需要2 ^ 60次bcrypt迭代来为这些密码提供强大的安全性,但这对好人来说实在太多了。尝试自己解决这个问题。关于什么是熵有很多资源-这不是解释/询问熵的地方。熵是您必须了解的基本概念,才能了解密码安全性。

– D.W.
2015年2月8日在1:51



#2 楼

简短版本

至少需要250毫秒的迭代次数

长版本

BCrypt于1999年首次发布时,它们列出了其实现的默认成本因素:


普通用户:6

超级用户:8 6表示64轮(26 = 64)。不定时



在1976年部署时,crypt每秒可以散列少于4个密码。 (每个密码250毫秒)
在1977年,在VAX-11 / 780上,每秒可对加密(MD5)进行约3.6次评估。 (每个密码277毫秒)

给您一种原始实现者在编写它时所考虑的延迟类型:


〜250毫秒对于普通用户
〜1秒对于超级用户。

但是,当然,您可以站立的时间越长越好。我见过的每个BCrypt实现都使用10作为默认成本。我的实现使用了这一点。我认为现在是时候将默认成本增加到12了。

我们决定将每个哈希的目标时间不少于250ms。是3.50 GHz的Intel Core i7-2700K CPU。我最初在2014年3月3日对BCrypt实现进行了基准测试:

1/23/2014  Intel Core i7-2700K CPU @ 3.50 GHz

| Cost | Iterations        |    Duration |
|------|-------------------|-------------|
|  8   |    256 iterations |     38.2 ms | <-- minimum allowed by BCrypt
|  9   |    512 iterations |     74.8 ms |
| 10   |  1,024 iterations |    152.4 ms | <-- current default (BCRYPT_COST=10)
| 11   |  2,048 iterations |    296.6 ms |
| 12   |  4,096 iterations |    594.3 ms |
| 13   |  8,192 iterations |  1,169.5 ms |
| 14   | 16,384 iterations |  2,338.8 ms |
| 15   | 32,768 iterations |  4,656.0 ms |
| 16   | 65,536 iterations |  9,302.2 ms |




未来的证明
而不是具有固定的常数,它应该是一个固定的最小值。

而不是让您的密码哈希函数为:

String HashPassword(String password)
{
   return BCrypt.HashPassword(password, BCRYPT_DEFAULT_COST);
}


它应该是就像这样:

String HashPassword(String password)
{  
   /*
     Rather than using a fixed default cost, run a micro-benchmark
     to figure out how fast the CPU is.
     Use that to make sure that it takes **at least** 250ms to calculate
     the hash
   */
   Int32 costFactor = this.CalculateIdealCost();
   //Never use a cost lower than the default hard-coded cost
   if (costFactor < BCRYPT_DEFAULT_COST) 
      costFactor = BCRYPT_DEFAULT_COST;

   return BCrypt.HashPassword(password, costFactor);
}

Int32 CalculateIdealCost()
{
    //Benchmark using a cost of 5 (the second-lowest allowed)
    Int32 cost = 5;

    var sw = new Stopwatch();
    sw.Start();
    this.HashPassword("microbenchmark", cost);
    sw.Stop();

    Double durationMS = sw.Elapsed.TotalMilliseconds;

    //Increasing cost by 1 would double the run time.
    //Keep increasing cost until the estimated duration is over 250 ms
    while (durationMS < 250)
    {
       cost += 1;
       durationMS *= 2;
    }

    return cost;
}


理想情况下,它应该是每个人的BCrypt库的一部分,因此,不是依靠库的用户来定期增加成本,而是定期增加成本本身。

评论


很棒的帖子,尽管我建议不要随着时间的推移自动增加成本。摩尔定律更多地是关于晶体管密度而不是CPU性能,后者在过去几年中显示出相当缓慢的增长。同样,摩尔定律也将要碰壁,我们需要改变处理器的基本技术才能继续发展。尽管如此,还是很漂亮的!

– andrewb
2015年10月20日在22:52



嗯如果微型基准测试运行时服务器处于负载状态,这是否还可以降低成本?

–约翰·莫拉汉(John Morahan)
2015年10月21日在20:28



@JohnMorahan不;它只会增加成本。见评论//永远不要使用低于默认硬编码成本的成本

–伊恩·博伊德(Ian Boyd)
15年10月22日在19:12

是的,但是如果已经自动将其增加,那么返回硬编码的下限仍然会减少。

–约翰·莫拉汉(John Morahan)
15年10月22日在22:45

假设您的下限是10,但是基于微基准,HashPassword决定现在在您的服务器上,13更合适。然后,您会被刀光剑影,每个人都注册并立即锤击您的网站。现在,微基准测试的运行速度变慢,并计算出11就是合适的成本。不是从10减少,而是从13减少。

–约翰·莫拉汉(John Morahan)
15年10月23日在8:15

#3 楼

通过顺序存储硬函数实现更强的密钥派生是有关密钥扩展的很好的论文。在第14页上,它比较了各种散列算法与破坏散列将花费多少钱,这是一种思考这些问题的有用方法。 (另一方面,如果TPM不可用,ChromeOS将使用Scrypt。)根据摩尔定律,这是一个指数级快速变化的目标。 Scrypt使用可变数量的内存和cpu,此变量可能会随时间变大。这样,每次客户端登录时,您都可以更新密码哈希,以提高安全性。对于PBKDF2,它看起来可能像rounds=2^(current_year-2000)或类似的东西。

重要的是要注意,您不能只是将此处理工作卸载到客户端上并期望您的协议是安全的。我所知道的所有客户端哈希认证协议都需要服务器进行相同的计算,以验证认证凭证(NTLM,NTLMv2,SRP,WPA-PSK ...)。

评论


我知道我应该符合摩尔定律。但这恰好是我的问题:考虑到当前的蛮力速度,如今多少次迭代被认为是安全的?

–Jason Smith
2012年7月14日在21:47

@杰森·史密斯(Jason Smith)我认为没有人能给您真实的数字,因为它是偶然的。我的回答是2 ^ 12,即4096,我的理由是因为其2012。

–rook
2012年7月14日在22:02



啊,我认为2 ^(current_year-2000)只是一个任意例子。好的,所以2012年有12发

–Jason Smith
2012年7月15日在10:44



@ D.W。 4096次迭代比我见过的大多数实现都大,请记住,明年将是8192 ...

–rook
2012年7月15日在23:42

@Rook,我和你在一起!我只是指出Jason Smith对于12轮与2 ^ 12轮之间的差异似乎感到困惑。

– D.W.
2015年2月7日在20:50