最佳的bcrypt工作因子

Chr*_*ris 78 bcrypt

什么是密码散列的理想bcrypt工作因素.

如果我使用因子10,在我的笔记本电脑上散列密码需要大约1秒.如果我们最终得到一个非常繁忙的网站,那么只需检查一下人们的密码即可完成大量工作.

也许最好使用7的工作因子,将每个笔记本电脑登录的总密码哈希工作减少到大约0.01秒?

您如何决定暴力安全与运营成本之间的权衡?

Jam*_*mes 100

请记住,该值存储在密码中:$2a$(2 chars work)$(22 chars salt)(31 chars hash).它不是固定值.

如果您发现负载过高,只需在下次登录时进行加密,就可以更快地加密计算.同样,随着时间的推移,您可以获得更好的服务器,如果负载不是问题,您可以在登录时升级其哈希的强度.

诀窍在于,随着摩尔定律,它将永远保持与未来相同的时间.该数字为log2,因此每次计算机速度加倍时,请将默认数字加1.

决定你需要多长时间来暴力破解用户的密码.例如,对于一些常见的字典单词,您的帐户创建可能已经警告他们密码很弱.如果它是1000个常用词之一,比如说,攻击者需要0.1秒来测试每个词,那就买100秒(好吧,有些词更常见......).如果用户选择"常用字典单词"+ 2个数字,那就超过两个小时.如果您的密码数据库遭到入侵,并且攻击者每天只能获得几百个密码,那么您已经在几小时或几天内购买了大部分用户来安全地更改密码.这是购买时间的问题.

http://www.postgresql.org/docs/8.3/static/pgcrypto.html有时会破解密码供您考虑.当然,他们在那里列出的密码是随机字母.字典词......实际上你不能保存密码为12345的人.

  • 这真是一个很好的答案.我甚至没有考虑过登录想法的重新加密.非常感谢! (8认同)
  • @JerrySaravia bcrypt的优点在于成本存储在哈希本身中 - 因此您不需要存储_anything_ extra.只需使用当前哈希进行身份验证,然后立即以不同的成本重新生成哈希.简单! (6认同)

Ian*_*oyd 7

精简版

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

长版

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

  • 普通用户:6
  • 超级用户:8

bcrypt 成本为6意味着 64 轮(2 6 = 64)。

他们还指出:

当然,人们选择的任何成本都应该不时重新评估

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

这让您了解原始实现者在编写它时考虑的那种延迟:

  • 普通用户约 250 毫秒
  • 超级用户约 1 秒。

但是,当然,你能站得越久越好。我见过的每个 BCrypt 实现都用作10默认成本。而我的实现使用的。我相信现在是我将默认成本增加到 12 的时候了。

我们已经决定我们希望每个哈希不低于 250 毫秒。

我的台式电脑是 Intel Core i7-2700K CPU @ 3.50 GHz。我最初在 2014 年 1 月 23 日对 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 |
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

面向未来

而不是有一个固定的常数,它应该是一个固定的最小值

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

String HashPassword(String password)
{
   return BCrypt.HashPassword(password, BCRYPT_DEFAULT_COST);
}
Run Code Online (Sandbox Code Playgroud)

它应该是这样的:

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;
}
Run Code Online (Sandbox Code Playgroud)

理想情况下,这将成为每个人的 BCrypt 库的一部分,因此与其依赖库的用户定期增加成本,成本本身也会定期增加。


Sam*_*ade 6

我一直在尝试确定 bcrypt salting 轮次的最佳数量,并想发布我的发现。正如其他人指出的那样,理想的轮数取决于您的硬件、用户的耐心以及潜在攻击者的硬件。

\n

2023 年,我在基本的 Heroku dyno 上运行,然后再次在我的本地计算机上运行,​​对一系列不同的盐轮进行哈希操作所需的时间进行了基准测试:

\n
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n
盐轮heroku 哈希时间5600x 哈希时间破解弱密码(28位)破解介质密码(37位)
713毫秒8毫秒12天17年
824 毫秒15毫秒23天32岁
947 毫秒29 毫秒1.5个月63岁
1090毫秒58毫秒3个月126 年
11181 毫秒118 毫秒6个月256 年
12367 毫秒233 毫秒1年很久
13735 毫秒461 毫秒2年
141422 毫秒936 毫秒4年
152878 毫秒1863 毫秒8年
165969 毫秒3721 毫秒16年
\n
\n

基于著名 XKCD 密码漫画的弱密码熵位数

\n

需要记住的因素:

\n
    \n
  • 破解时间可以除以您可以访问的计算机数量。拥有僵尸网络或大量资金的黑客可以将这些破解时间划分为几个数量级

    \n
  • \n
  • 裂纹时间随着时间的推移而减少。现在泄露的散列密码可能在 10 年后很容易被破解。

    \n
  • \n
  • 5600X 距离现代处理的顶峰还很远。7900X能够更快地完成此操作。

    \n
  • \n
  • 这是单线程完成的,多线程会使它更快。

    \n
  • \n
\n

根据此数据,我建议至少 10 轮,但强烈建议 11 轮。100-200 毫秒对于用户来说等待时间非常短,如果并发登录导致延迟,您应该考虑为您的后端添加更多马力。我最多建议是13轮。虽然它非常安全,但 700 毫秒对于用户等待登录来说是很长的时间。在 10 到 13 毫秒之间,这将是您作为开发人员需要做出的判断。

\n

PS:我想赞扬 Ian Boyds 非常好的图表和非常好的自动缩放代码。这是每个阅读本文的人都应该考虑的事情,但我也想提供一些最新数据,说明 bcrypt 在当前和常见硬件上今年实际需要多长时间。

\n

如果这个答案已经过时,请发表评论,我会尽力抽出时间来更新它。

\n

注意:如何计算破解时间?

\n

要讨论这个问题,我们首先必须讨论密码熵。非常简单:密码熵是根据您用来选择密码的系统计算的。因此,如果您的密码是 4 位 PIN 码,则您只能选择 10,000 个可能的 PIN 码。因此,您的密码的熵为 10,000。这通常被称为 13 位熵,因为 10,000 \xe2\x89\x88 2\xc2\xb9\xc2\xb3。

\n

要确定攻击者破解您的密码需要多长时间,您只需确定他们平均需要猜测多少次。对于那个 4 位数字的 PIN 码,他们可以在第一次尝试时猜出,或者需要 10,000 次尝试。但攻击者平均需要尝试 5,000 次。所以检查单个密码所需的时间乘以所需猜测的次数就是破解时间。

\n