关于php:什么是密码强度,足以与password_hash函数一起使用?

What is password strength considered enough for use with password_hash function?

据我所知,新的php密码散列扩展(通常是bcrypt)最重要的特性之一是算法的速度,这大大降低了暴力攻击方法的速度。

但它仍然以一定的速度运行,足以让字典攻击和暴力地强制弱密码,[据说]少于六个字母数字字符。

所以我想知道,它是如何的缓慢,尤其是-哪个密码强度被认为是安全的使用。"如你所能想象的那么强大"不是一个答案,因为密码强度总是安全性和可用性之间的权衡-所以,我在寻找可以被认为是安全的最小强度,甚至是未来的证据。

请注意,我是一个实事求是的人,因此,基于具体数字的某些答案比带有不确定结论的冗长而冗长的理论推理更可取。

为了更清楚一点,最糟糕的情况应该是:用户数据库被盗,有人会试图破译密码。由于盐太多,彩虹桌不是一个选择。所以,只剩下字典攻击和暴力。假设我们向用户提供预先生成的密码,消除字典攻击。这就是为什么密码强度是我唯一关心的问题。

更新:我好像不太明白。对我来说,这个问题很实际,而且是可以回答的。非常重要。

如果不确定足够的密码强度,这个新算法的使用可能会受到质疑。如果密码仍然不安全,为什么还要考虑好的算法呢?所以,我坚信,除了推荐使用新的哈希算法之外,还应该始终推荐最小密码强度。我想知道。

换言之,如果一部分算法存在特定的确定性("使用这一部分,而不是其他部分!")-显然,还应该确定另一个部分-密码强度,它可以以相同的权限进行对话。否则最弱的部分会破坏最强的部分。


我不确定我是否清楚地理解您的问题,但我只关注密码强度以及它如何影响蛮力攻击。

But still it runs at some speed, surely enough for the dictionary attack and to brute-force weak passwords, [supposedly] shorter than six alphanumeric characters.

介绍

暂时忘记哈希算法(md5、sha、pbkdf2-bcrypt、scrypt等),以免先关注密码强度。

密码强度wiki

这是衡量密码在抵御猜测和暴力攻击方面的有效性的一个指标。在其通常的形式中,它估计没有直接访问密码的攻击者平均需要多少次测试来正确猜测密码。

它可以简单地计算为:

enter image description here

熵由H=Llog2N给出,其中L是密码的长度,N是字母表的大小,通常用位来度量。

哈希函数

默认情况下,password_hash使用[bcrypt][4]就足够输入密码了,但有更好的选择,如pbkdf2或scrypt,以获取有关我所说的如何安全存储密码的更多信息。

使用oclhashcat,让我们估计以下内容

1
2
3
4
5
6
+--------+-----------+----------------+
|  HASH  | ESTIMATE  |     BITS/S     |
+--------+-----------+----------------+
| MD5    | 10742M    | 90110427136    |
| BCRYPT | 31M       | 260046848      |
+--------+-----------+----------------+

请注意,这是一个估计值,可能因硬件容量而异。

有了这些信息,我们就可以安全地计算出暴力破解不同密码需要多长时间。

用php计算熵

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$passwords = array(
       "1234",
       "F2A1CC",
       "password",
       "PaSSworD",
       "P4ssw0Rd97",
       "p#aSS*Word14",
       "Dance With Me Tonight"
);

print("PASSWORD\tLENGTH\tENTROPY\tTIME MD5\tTIME BCRYPT
"
);

foreach($passwords as $password ){

    printf("%s\t%s\t%s\t%s\t%s
"
,
        $password,
        strlen($password),
        $entropy = calculateEntropy($password),
        totalTime($entropy,"90110427136"),     // Check with MD5
        totalTime($entropy,"260046848")        // Check with BCrypt
    );
}

产量

1
2
3
4
5
6
7
8
9
10
11
+-----------------------+--------+---------+------------+----------------+
|       PASSWORD        | LENGTH | ENTROPY |  TIME MD5  |  TIME BCRYPT   |
+-----------------------+--------+---------+------------+----------------+
| 1234                  |      4 |  13.29  | 1min       | 1min           |
| F2A1CC                |      6 |  24.00  | 1min       | 1min           |
| password              |      8 |  37.60  | 1min       | 1min           |
| PaSSworD              |      8 |  45.60  | 1min       | 1day+          |
| P4ssw0Rd97            |     10 |  59.54  | 2mo+       | 71yr+          |
| p#aSS*Word14          |     12 |  75.86  | 13,479yr+  | 4yr+           |
| Dance With Me Tonight |     21 |  120.29 | 474,250yr+ | 164,335,595yr+ |
+-----------------------+--------+---------+------------+----------------+

使用csv2表转换的输出

密码破解器的CUDA/Opencl实现可以利用GPU中的大量并行性,最高可达每秒数十亿个候选密码。

让我们来估计一下,我们可以在非常快的系统上并行执行921600M c/s

1
2
T = 966367641600 * 8  
T = 7,730,941,132,800  // bits/sec

使用

1
2
3
4
5
6
7
8
9
foreach($passwords as $password ){  
    printf("%s\t%s\t%s\t%s
"
,
        $password,
        strlen($password),
        $entropy = calculateEntropy($password),
        totalTime($entropy,"7730941132800")        // Check with Hash
    );
}

产量

1
2
3
4
5
6
7
8
9
10
11
+-----------------------+---------+---------+----------+
|       PASSWORD        | LENGTH  | ENTROPY |   TIME   |
+-----------------------+---------+---------+----------+
| 1234                  |       4 | 13.29   | 1min     |
| F2A1CC                |       6 | 24.00   | 1min     |
| password              |       8 | 37.60   | 1min     |
| PaSSworD              |       8 | 45.60   | 1min     |
| P4ssw0Rd97            |      10 | 59.54   | 20hr+    |
| p#aSS*Word14          |      12 | 75.86   | 157yr+   |
| Dance With Me Tonight |      21 | 120.29  | 5,527yr+ |
+-----------------------+---------+---------+----------+

正如你所看到的,一个12位数的数字被打破还需要一段时间。

使用的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
// Calculate Password entropy
// Uses H = L Log2 N
// where L is the length of the password and
// N is the size of the alphabet, and it is usually measured in bits
function calculateEntropy($password) {

    // See http://en.wikipedia.org/wiki/Password_strength
    // Entropy per symbol for different symbol sets
    // Missing All extended ASCII printable characters
    // Missing Diceware word list

    // TODO
    // Larger Character Set
    // '/[\!"#$%&\'\(\)\*\+,\-.\/:;<\=>\?\@\[\]^_`\{|\}~]+/' => 32,
    $cases = array(
           "/\s+/" => 1, // Arabic numerals (0–9) (e.g. PIN)
           "/[0-9]+/" => 10, // Arabic numerals (0–9) (e.g. PIN)
           "/[a-z]+/" => 26, // Case insensitive Latin alphabet (a-z)
           "/[A-Z]+/" => 26, // Case insensitive Latin alphabet (A-Z)
            '/[\!\@#$%\?\&\*\(\)_\-\+=~:;.]+/i' => 18  // Other Character
        );

    $L = strlen($password); // Length of password
    $N = 0; // Character Set

    foreach($cases as $regex => $value ){
        if (preg_match($regex, $password)){
            $N += $value;
        }
    }

    // Don't confuse hexadecimal for alpha numeric characters
    // hexadecimal numerals (0–9, A-F) (e.g. WEP keys)
    if (ctype_xdigit($password)){
        $N = 16;
    }

    // Fix pure number cases that might have been changed by hexadecimal
    // Arabic numerals (0–9) (e.g. PIN)
    if (ctype_digit($password)){
        $N = 10;
    }

    // Using H = L Log2N
    // See http://en.wikipedia.org/wiki/Password_strength
    // Random passwords entropy
    $H = $L * log($N, 2);
    return number_format($H, 2);
}

// Claculate Total time it would take
// Using Entropy & froce / s
function totalTime($entropy, $force) {
    bcscale(0);

    // Total Base on entorpy 2^H
    $total = bcpow(2, $entropy);

    // Time Taken per sec on Force
    $ss = bcdiv($total, $force);

    $time ="";
    $parts = [];

    $parts['yr'] = bcdiv($ss,"31104000");
    $parts['mo'] = bcdiv(bcmod($ss, 31104000), 2592000);
    $parts['day'] = bcdiv(bcmod($ss, 2592000), 86400);
    $parts['hr'] = bcdiv(bcmod($ss, 86400), 3600);

    // Clean Year
    // Can really generate large numbers

    $suffix ="";
    $yr = $parts['yr'];
    if (!empty($yr)){
        if (bccomp($yr,"1000000") > 0){
            $parts['yr'] = bcdiv($yr,"1000000"); // Million
            $year =" million";
        }

        if (bccomp($yr,"1000000000") > 0){
            $parts['yr'] = bcdiv($yr,"1000000000"); // Billion
            $year =" billion";
        }

        if (bccomp($yr,"1000000000000") > 0){
            $parts['yr'] = bcdiv($yr,"1000000000000"); // Trillion
            $year =" trillion";
        }
    }

    foreach($parts as $t => $v ){
        if (empty($v)){
            continue;
        }
        $time .= number_format($v, 0) . $suffix . $t ."+";
        break;
    }

    return empty($time) ?"1min" : $time;
}

误解

你是正确的密码长度是重要的,所以密码的熵。大多数建议建议用户在不了解密码强度的情况下使用bcrypt、密码复杂性等。

但事实上,最简单的密码往往是最强的。

氧化镁

来源相关博客帖子

So I want to know, how it's certainly slow, and, particularly - which password strength considered safe to be used with.

氧化镁来源

肯定不是6 letters

  • <28位=非常弱;可能会将家庭成员拒之门外
  • 28-35位=弱;应该避开大多数人,通常对桌面登录密码很好
  • 36-59位=合理;网络密码和公司密码相当安全
  • 60-127位=强;可以很好地保护财务信息
  • 128+位=非常强;通常是杀伤力过大

结论

这里有一些很好的参考资料,你可以看看什么

  • 彩虹桌死了
  • oclhashcat公司
  • 如何安全存储密码
  • 不使用bcrypt
  • 密码熵
  • 密码强度/熵:字符与字
  • 密码的熵是多少?
  • Kolmogorov复杂性


这是一个有趣的问题,尽管任何人都不太可能给出最后的答案。

如您所知,bcrypt(和其他关键派生函数)具有成本因素。通常,您会调整这个成本因素,直到您的服务器需要一定的时间来散列密码,例如1毫秒。因此,具有相同硬件的攻击者可以计算1000个哈希/秒。

如果您将oclhashcat(gpu)的速度与其CPU版本进行比较,您会发现MD5的系数为100,因此我们可以猜测攻击者可以野蛮地处理大约1000'000个哈希/秒(bcrypt不支持GPU,但要在安全方面…)。这是从8000'000'000 MD5哈希/秒开始的方法,取决于成本因素。

第二个问题是密码的坚固性。如果它是普通字典的一部分,即使它很长也能很快找到,因此最小长度并不能保证使用强密码。如果它足够"随机",那么破解它的唯一方法就是暴力强迫(对我们来说是最好的例子)。对于这种情况,我们可以尝试一些数学方法:

1
2
3
4
Password alphabet: 62 characters (a-z A-Z 0-9)
Combinations to try: half of all possible combinations
Password length 7: 3E12 combinations → 20 days
Password length 8: 2E14 combinations → 3-4 years

当然,这是基于很多假设的,也许攻击者可以更快地使用暴力,或者密码不够强大。我自己要求至少8个字符,但建议使用密码。

编辑:关于密码强度的另一个注意事项:

密码的强度不能实际计算,当然不能通过公式计算。每一个严重的密码破解工具将支持混合攻击和基于规则的攻击。如果密码是字典的一部分或是被规则处理,那么看起来很强的密码可能非常弱,因此这取决于攻击者的想象力,密码破解的速度有多快。

唯一能告诉我们的是,长密码和随机密码都很强,因为没有比强行破解更容易的方法了。但这在这里没有帮助,因为用户会选择他们的密码,而不是建立网站的开发人员,而且他们不会选择理想的密码。


根据您最近的评论,您希望构建一个主要政府可以接受的密码方案。这些信息随时可用。

  • FIPS 112,美国政府要求的标准。
  • 欧盟密码准则