【问题标题】:Optimal bcrypt work factor最佳 bcrypt 工作因子
【发布时间】:2011-05-25 12:22:15
【问题描述】:

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

如果我使用 10 倍,在我的笔记本电脑上散列密码大约需要 0.1 秒。如果我们最终得到一个非常繁忙的网站,那么仅检查人们的密码就会变成大量工作。

也许使用 7 的工作系数会更好,将每次笔记本电脑登录的总密码哈希工作减少到大约 0.01 秒?

您如何在蛮力安全和运营成本之间做出权衡?

【问题讨论】:

  • 阻止离线攻击的成本。当“在线”时,您可以在尝试之间使用最小延迟(例如 5 秒)来防止拒绝服务攻击。
  • 在信息安全上重复:Recommended # of rounds for bcrypt
  • 对于任何感兴趣的人,我刚刚编写了一个小型 Java CLI 工具来测试服务器上的 bcrypt 性能(这对于平衡安全性、服务器负载和响应时间显然很重要):github.com/cdraeger/hash-performance

标签: bcrypt


【解决方案1】:

这个问题与 bcrypt 密码哈希的成本因子的最佳和实际确定有关。

在您计算服务器的用户密码哈希值的系统上,您预计用户数量会随着时间的推移而增长,为什么不将用户拥有您的服务帐户的持续时间作为决定因素,也许包括他们的登录频率作为该决定的一部分。

Bcrypt 成本系数 = 6 +(用户成员资格年数或其某个因素),总成本有一个可选上限,可能会因该用户的登录频率而以某种方式进行修改。

请记住,尽管使用这样的系统或任何系统来有效地确定成本因素必须考虑到计算哈希的成本可以用作针对服务器本身的 DDOS 攻击的方法,方法是考虑到任何增加攻击的成本因素。

【讨论】:

    【解决方案2】:

    短版

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

    加长版

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

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

    6 的 bcrypt 成本意味着 64 轮(26 = 64)。

    他们还注意到:

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

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

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

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

    当然,你能站得越久越好。我见过的每个 BCrypt 实现都使用 10 作为默认成本。 my implementation 使用了它。我认为是时候将默认成本提高到 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 |
    

    面向未来

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

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

    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 库的一部分,因此与其依赖库的用户定期增加成本,不如定期增加成本。

    【讨论】:

      【解决方案3】:

      记住该值存储在密码中:$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 的人。

      【讨论】:

      • 这真是一个很好的答案。我什至没有考虑过重新加密登录的想法。非常感谢!
      • 重新加密如何工作?您必须将旧的 bcrypt 工作成本存储在某个地方,以便您可以使用它来登录,然后在验证他们的密码后,您将更新数据库中的哈希和成本?
      • @JerrySaravia bcrypt 的美妙之处在于成本存储在哈希本身中 - 因此您不需要额外存储 任何东西。只需使用当前哈希进行身份验证,然后立即以不同的成本重新生成哈希。简单!
      • @MarkLocker,谢谢马克!这是一个 B[美丽] 地穴!但说真的,这让事情变得更容易,而且是一件很棒的事情。
      • 好的,因为我不允许编辑它,因为这是“不正确的回复尝试”(你们甚至阅读我的编辑吗?),请允许我评论信息。示例值:$2y$08$fJS4yx0i8kiOzIBIamZ51OWTMrzyE/4je34Oxhw.5xxp3Es7Ke32W。我尝试编辑的原因:我不清楚“2 chars work”是数字还是十六进制或其他东西,必须测试。这是其他所有人的测试结果,因此您不必自己尝试。
      猜你喜欢
      • 2012-06-22
      • 2014-02-11
      • 1970-01-01
      • 2017-08-09
      • 1970-01-01
      • 2020-09-06
      • 2015-04-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多