8

据我了解,新的PHP 密码散列扩展(或一般 bcrypt)最重要的特性之一是算法的速度,它大大降低了蛮力攻击方法。

但它仍然以某种速度运行,对于字典攻击和暴力破解弱密码来说肯定足够了,[据说]短于六个字母数字字符。

所以我想知道,它确实很慢,特别是 - 使用哪种密码强度被认为是安全的。“尽可能强大”不是答案,因为密码强度始终是安全性和可用性之间的权衡 - 因此,我正在寻找可以被认为是安全的最小强度,甚至是一些面向未来的强度。

请注意,我是一个实践者 - 因此,基于具体数字的特定答案比具有不确定结论的冗长而冗长的理论推理更可取。

为了澄清一点,假设最坏的情况是:用户数据库被盗,有人会试图破译密码。多亏了强盐,彩虹桌不是一种选择。因此,剩下的唯一向量是字典攻击和蛮力。假设我们为用户提供预先生成的密码,消除字典攻击。这就是为什么密码强度是我唯一关心的原因。

更新:
似乎我没有很好地理解。对我来说,这个问题非常实用,而且可以回答。并且非常重要

在没有确定足够的密码强度的情况下,这种新算法的使用可能会受到质疑。如果密码仍然不安全,为什么还要使用好的算法呢?所以——我坚信——除了推荐使用新的散列算法外,还应该始终推荐最低密码强度。我想知道。

换句话说,如果某个部分存在特定的确定性 - 算法(“使用这个,而不是另一个!”) - 显然应该确定另一部分 - 密码强度,可以以相同级别的权限说出来。否则最弱的部分会破坏最强的部分。

4

3 回答 3

36

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

但它仍然以某种速度运行,对于字典攻击和暴力破解弱密码来说肯定足够了,[据说]短于六个字母数字字符。

介绍

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

密码强度 维基

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

它可以简单地计算为:

在此处输入图像描述

熵由H=Llog2NwhereL是密码的长度和N字母的大小给出,通常以位为单位。

哈希函数

password_hash默认情况下使用[bcrypt][4]with 就足够了密码,但有更好的选择,如PBKDF2scrypt了解更多关于我的意思的信息,请参阅如何安全地存储密码

使用oclHashcat,让我们估计以下

+--------+-----------+----------------+
|  HASH  | ESTIMATE  |     BITS/S     |
+--------+-----------+----------------+
| MD5    | 10742M    | 90110427136    |
| BCRYPT | 31M       | 260046848      |
+--------+-----------+----------------+

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

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

在 PHP 中计算熵

$passwords = array(
        "1234",
        "F2A1CC",
        "password",
        "PaSSworD",
        "P4ssw0Rd97",
        "p#aSS*Word14",
        "Dance With Me Tonight" 
);

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

foreach($passwords as $password ){

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

输出

+-----------------------+--------+---------+------------+----------------+
|       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+ |
+-----------------------+--------+---------+------------+----------------+

使用 csv2table 转换的输出

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

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

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

使用

foreach($passwords as $password ){  
    printf("%s\t%s\t%s\t%s\n", 
        $password, 
        strlen($password), 
        $entropy = calculateEntropy($password), 
        totalTime($entropy, "7730941132800")        // Check with Hash
    );
}

输出

+-----------------------+---------+---------+----------+
|       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 位数字仍然需要一段时间。

使用的功能

// 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 、密码复杂性等

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

在此处输入图像描述

来源| 相关博文

所以我想知道,它确实很慢,特别是 - 使用哪种密码强度被认为是安全的。

在此处输入图像描述 资源

绝对不是6 letters:)

  • < 28 位 = 非常弱;可能会阻止家庭成员
  • 28 - 35 位 = 弱;应该阻止大多数人,通常适用于桌面登录密码
  • 36 - 59 位 = 合理;相当安全的网络密码和公司密码
  • 60 - 127 位 = 强;可以很好地保护财务信息
  • 128+ 位 = 非常强;经常矫枉过正

结论

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

于 2014-02-10T04:52:27.120 回答
3

这是一个有趣的问题,尽管不太可能有人能够给出最终答案。

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

如果您将oclHashcat (GPU) 的速度与其 CPU 版本进行比较,您会看到 MD5 的因子为 100,因此我们可以猜测攻击者可以暴力破解大约 1'000'000 哈希/秒(BCrypt 对 GPU 不友好,但要为了安全起见...)。这是 8'000'000'000 MD5 哈希/秒的方法,取决于成本因素。

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

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 个字符,但建议使用密码。

编辑:关于密码强度的另一个说明:

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

我们唯一能说的是,长而随机的密码很强大,因为没有比暴力破解更容易的方法了。但这在这里无济于事,因为用户会选择他们的密码,而不是建站的开发者,他们也不会选择理想的密码。

于 2014-02-07T15:38:52.277 回答
0

根据您的最新评论,您希望构建一个主要政府可以接受的密码方案。这些信息很容易获得。

于 2014-02-06T17:38:12.750 回答