Какая надежность пароля считается достаточной для использования с функцией password_hash?

Насколько я понимаю, одной из наиболее важных особенностей нового расширения хеширования паролей PHP (или bcrypt в целом) является скорость алгоритма, которая сильно замедляет метод атаки методом перебора.

Но, тем не менее, он работает с некоторой скоростью, безусловно, достаточной для атаки по словарю и грубого взлома слабых паролей, [предположительно] короче шести буквенно-цифровых символов.

Итак, я хочу знать, как это, конечно, медленно, и, в частности, - с какой надежностью пароля считается безопасным для использования. "Столько, сколько вы можете себе представить" - это не ответ, так как надежность пароля - это всегда компромисс между безопасностью и удобством использования - поэтому я ищу минимальную надежность, которую можно считать безопасной и даже перспективной.

Пожалуйста, обратите внимание, что я человек практики - поэтому определенный ответ, основанный на конкретных числах, гораздо предпочтительнее, чем длинные и ветреные теоретические рассуждения с неопределенным выводом.

Чтобы прояснить это немного, предполагается худший сценарий: пользовательская база данных украдена, и кто-то попытается расшифровать пароли. Радужные столы не вариант из-за сильной соли. Таким образом, единственными оставшимися векторами являются атака по словарю и перебор. Предполагая, что мы снабжаем пользователей предварительно сгенерированными паролями, исключая атаки по словарю. Вот почему надежность пароля - моя единственная забота.

Обновить:
Кажется, меня плохо поняли. Вопрос для меня вполне практичен и довольно ответственно. И имеет большое значение.

Без определения достаточной надежности пароля использование этого нового алгоритма может быть поставлено под сомнение. Зачем использовать хороший алгоритм, если пароли все еще остаются небезопасными? Поэтому я твердо убежден, что наряду с рекомендациями по использованию нового алгоритма хеширования всегда должна быть рекомендация относительно минимальной надежности пароля. Что я хочу знать.

Другими словами, если существует определенная уверенность в отношении одной части - алгоритма ("используйте эту, а не другую!"), - очевидно, должна быть уверенность в другой части - надежности пароля, о которой можно говорить с тем же уровнем полномочий. Иначе самая слабая часть испортит самую сильную.

3 ответа

Не уверен, что я правильно понимаю ваш вопрос, но я бы просто сосредоточился на надежности пароля и его влиянии на атаку методом перебора.

Но все же он работает с некоторой скоростью, конечно, достаточно для атаки по словарю и для грубых взломов слабых паролей, [предположительно] короче шести буквенно-цифровых символов.

Вступление

На мгновение забудьте о алгоритме хеширования (md5, sha, pbkdf2 bcrypt, scrypt и т. Д.) И прежде всего не обращайте внимания на надежность пароля

Надежность пароля вики

Это мера эффективности пароля в противостоянии угадыванию и атакам методом перебора. В своей обычной форме он оценивает, сколько попыток злоумышленнику, не имеющему прямого доступа к паролю, в среднем потребуется, чтобы правильно его угадать.

Это можно просто рассчитать как:

Энтропия дается H=Llog2N где L длина пароля и N это размер алфавита, и он обычно измеряется в битах.

Хэш-функция

password_hash использования [bcrypt][4] по умолчанию с паролем достаточно, но есть лучшие альтернативы, такие как PBKDF2 или scrypt для получения дополнительной информации о том, что я имею в виду, см. Как безопасно хранить пароль

Используя 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 могут использовать огромное количество параллелизма, доступного в графических процессорах, достигая миллиардов паролей-кандидатов в секунду.

Давайте оценим, что мы можем сделать 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+ бит = очень сильный; часто перебор

Заключение

Вот несколько хороших ссылок, на которые вы можете посмотреть

Это интересный вопрос, хотя вряд ли кто-нибудь сможет дать окончательный ответ.

Как вы знаете, BCrypt (и другие функции получения ключей) имеют фактор стоимости. Обычно вы настраиваете этот фактор стоимости, пока вашему серверу не понадобится определенное время для хеширования пароля, например, 1 миллисекунда. Таким образом, злоумышленник с таким же оборудованием может рассчитать 1000 хэш / с.

Если вы сравните скорость oclHashcat (GPU) с его версией процессора, вы увидите коэффициент 100 для MD5, поэтому мы можем предположить, что злоумышленник может использовать приблизительно 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 символов, но рекомендую использовать фразу-пароль.

РЕДАКТИРОВАТЬ: Еще одно примечание о надежности пароля:

Надежность пароля не может быть рассчитана реально, конечно же, не по формуле. Каждый серьезный инструмент для взлома паролей будет поддерживать гибридные атаки и атаки на основе правил. Пароли, выглядящие надежно, могут быть очень слабыми, если они являются частью словаря или управляются по правилу, поэтому от того, насколько быстро может быть взломан пароль, зависит воображение злоумышленника.

Единственное, что мы можем сказать, это то, что длинные и случайные пароли являются надежными, потому что нет более простого способа взломать их, чем перебор. Но это здесь не поможет, потому что пользователи будут выбирать свои пароли, а не разработчика, который создал сайт, и они не выбирают идеальные пароли.

Согласно вашему последнему комментарию, вы хотите создать схему паролей, которая была бы приемлема для крупных правительств. Эта информация легко доступна.

Другие вопросы по тегам