Как хэшировать длинные пароли (>72 символов) с blowfish


на прошлой неделе я прочитал много статей о хэшировании паролей и Blowfish, похоже, является (одним из) лучшим алгоритмом хэширования прямо сейчас - но это не тема этого вопроса!

предел 72 символов

Blowfish рассматривает только первые 72 символа в введенном пароле:

<?php
$password = "Wow. This is a super secret and super, super long password. Let's add some special ch4r4ct3rs a#d everything is fine :)";
$hash = password_hash($password, PASSWORD_BCRYPT);
var_dump($password);

$input = substr($password, 0, 72);
var_dump($input);

var_dump(password_verify($input, $hash));
?>

выход:

string(119) "Wow. This is a super secret and super, super long password. Let's add some special ch4r4ct3rs a#d everything is fine :)"
string(72) "Wow. This is a super secret and super, super long password. Let's add so"
bool(true)

как вы можете видеть только первые 72 символа вопроса. Twitter использует blowfish aka bcrypt для хранения своих паролей (https://shouldichangemypassword.com/twitter-hacked.php) и угадайте, что: измените свой пароль twitter на длинный пароль с более чем 72 символами, и вы можете войти в свой аккаунт, введя только первые 72 символа.

Blowfish и перец

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

в этом случае (перец не просочился) вы делаете атаку на основе словаря сложнее (поправьте меня, если это не так). Если ваша перечная струна также просочилась: не так уж плохо-у вас все еще есть соль, и она так же хорошо защищена, как хэш без перца.

так что я думаю, что перец пароль, по крайней мере, не плохо выбор.

предложение

мое предложение, чтобы получить Blowfish хэш для пароля с более чем 72 символов (и перец) является:

<?php
$pepper = "foIwUVmkKGrGucNJMOkxkvcQ79iPNzP5OKlbIdGPCMTjJcDYnR";

// Generate Hash
$password = "Wow. This is a super secret and super, super long password. Let's add some special ch4r4ct3rs a#d everything is fine :)";
$password_peppered = hash_hmac('sha256', $password, $pepper);
$hash = password_hash($password_peppered, PASSWORD_BCRYPT);

// Check
$input = substr($password, 0, 72);
$input_peppered = hash_hmac('sha256', $input, $pepper);

var_dump(password_verify($input_peppered, $hash));
?>

это основано на этот вопрос:password_verify возвращение false.

Вопрос

что является более безопасным способом? Сначала получить хэш SHA-256 (который возвращает 64 символа) или рассмотреть только первые 72 символа пароля?

плюсы

  • пользователь не может войти в систему, введя только первые 72 символа
  • вы можете добавить перец, не превышая лимит символов
  • выход hash_hmac, вероятно, будет иметь больше энтропии, чем сам пароль
  • пароль хэшируется двумя различными функциями

минусы

  • только 64 символа используются для создания blowfish хэш


Edit 1: этот вопрос касается только PHP интеграции blowfish / bcrypt. Спасибо за комментарии!

3 82

3 ответа:

проблема здесь в основном проблема энтропии. Так что давайте начнем искать там:

Энтропия На Символ

количество бит энтропии на байт:

  • Символы
    • биты: 4
    • значения: 16
    • энтропия в 72 символах: 288 бит
  • Альфа-Числовые
    • биты: 6
    • значения: 62
    • энтропия в 72 символов: 432 бит
  • "Общие" Символы
    • бит: 6.5
    • значения: 94
    • энтропия в 72 символах: 468 бит
  • Полный Байт
    • бит: 8
    • значения: 255
    • энтропия в 72 символах: 576 бит

Итак, как мы действуем, зависит от типа персонажей мы ожидаем.

Первая Проблема

первая проблема с вашим кодом, это ваш "перец" шаг хэша выводит шестнадцатеричные символы (начиная с четвертого параметра до hash_hmac() не установлен).

поэтому, хешируя свой перец, вы эффективно сокращаете максимальную энтропию, доступную паролю, в 2 раза (от 576 до 288 возможно bits).

Второй Проблема

однако, sha256 представлена только 256 биты энтропии в первую очередь. Таким образом, вы эффективно сокращаете возможные 576 бит до 256 бит. Ваш шаг хэша * немедленно*, по самому определению проигрывает по крайней мере 50% от возможно энтропии в пароле.

вы можете частично решить эту проблему, переключившись на SHA512, где вы только уменьшите доступную энтропию примерно на 12%. Но это все-таки не так уж и незначительно разница. Это на 12% уменьшает количество перестановок в разы 1.8e19. Это большое число... И это фактор уменьшает его...

Основная Проблема

основная проблема заключается в том, что существует три типа паролей более 72 символов. Влияние, которое эта система стилей оказывает на них, будет очень разным:

Примечание: отсюда я предполагаю, что мы сравниваем с системой перца, которая использует SHA512 с сырым выход (не шестигранной).

  • высокая энтропия случайных паролей

    это ваши пользователи, использующие генераторы паролей, которые генерируют какое количество больших ключей для паролей. Они случайны (генерируются, а не выбираются человеком) и имеют высокую энтропию на символ. Эти типы используют высокие байты (символы > 127) и некоторые управляющие символы.

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

    позвольте мне сказать это снова. Для пользователей, которые используют высокую энтропию, длинные пароли, решения значительно уменьшает силу их пароля на измеримую величину. (62 бита энтропии потеряно для 72 символов пароля, и больше для более длинных паролей)

  • случайные пароли средней энтропии

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

    для этой группы, вы собираетесь немного разблокировать больше энтропии (не создавать его, но позволить больше энтропии вписаться в пароль bcrypt). Когда я говорю немного, я имею в виду немного. Безубыточность возникает, когда вы максимизируете 512 бит, которые имеет SHA512. Таким образом, пик составляет 78 символов.

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

  • низкая энтропия неслучайные пароли

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

    для этой группы вы можете значительно разблокировать больше энтропии (не создавать ее, но разрешить больше вписываться в ввод пароля bcrypt) путем хэширования. Безубыток составляет около 223 символы, прежде чем закончится энтропия.

    скажем так еще раз. Для этого класса паролей предварительное хэширование определенно значительно повышает безопасность.

Назад В Реальный Мир

эти виды расчетов энтропии на самом деле не имеют большого значения в реальном мире. Главное-угадать энтропию. Это то, что непосредственно влияет на то, что могут сделать злоумышленники. Это то, что вы хотите максимизировать.

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

шансы случайно угадать 72 правильных символа в строкеочень низкий. У вас больше шансов выиграть в лотерею Powerball 21 раз, чем иметь это столкновение... Вот о каком количестве мы говорим.

но мы не можем наткнуться на это статистически. В случае фраз вероятность того, что первые 72 символа будут одинаковыми, - это много выше, чем для случайного пароля. Но это все еще тривиально низко (вы с большей вероятностью выиграете лотерею Powerball 5 раз, основываясь на 2,3 битах на символ).

практически

практически, это действительно не имеет значения. Шансы того, что кто-то угадает первые 72 символа правильно, где последние имеют существенное значение, настолько низки, что не стоит беспокоиться. Зачем?

ну, допустим, вы берете фразу. Если человек может получить первые 72 символа справа, они либо действительно повезло (вряд ли), или это общая фраза. Если это обычная фраза, единственная переменная-это как долго ее делать.

возьмем пример. Давайте возьмем цитату из Библии (просто потому, что это общий источник длинного текста, а не по любой другой причине):

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

это 180 символов. 73-й символ-это g во втором neighbor's. Если вы догадались, что много, вы, вероятно, не останавливаясь на nei, но продолжая с остальной частью стиха (так как пароль может быть использован). Таким образом, ваш "хэш" не добавил много.

кстати: я абсолютно не выступаю за использование цитаты из Библии. На самом деле, точное противоположный.

вывод

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

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

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

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

это мой $0.02 по крайней мере (или, возможно, намного больше, чем $0.02)...

Что Касается Использования" Секретного " Перца:

буквально нет исследований по подаче одной хэш-функции в bcrypt. Поэтому неясно, в лучшем случае, если подача "перченого" хэша в bcrypt когда-либо вызовет неизвестные уязвимости (мы знаем, что делаем hash1(hash2($value)) может подвергать значительные уязвимости вокруг сопротивления столкновению и предвидения атак).

учитывая, что вы уже рассматриваете возможность хранения секретного ключа ("перец"), почему бы не использовать это так хорошо изучено и понято? Почему бы не зашифровать хэш до его хранения?

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

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

Примечание: Если вы решите сделать это, используйте библиотеку. Для PHP, я сильно рекомендуем Zend Framework 2's Zend\Crypt пакета. Это на самом деле единственный, который я бы рекомендовал в данный момент времени. Он был сильно пересмотрен, и он принимает все решения за вас (что очень хорошо)...

что-то типа:

use Zend\Crypt\BlockCipher;

public function createHash($password) {
    $hash = password_hash($password, PASSWORD_BCRYPT, ["cost"=>$this->cost]);

    $blockCipher = BlockCipher::factory('mcrypt', array('algo' => 'aes'));
    $blockCipher->setKey($this->key);
    return $blockCipher->encrypt($hash);
}

public function verifyHash($password, $hash) {
    $blockCipher = BlockCipher::factory('mcrypt', array('algo' => 'aes'));
    $blockCipher->setKey($this->key);
    $hash = $blockCipher->decrypt($hash);

    return password_verify($password, $hash);
}

и это выгодно, потому что вы используете все алгоритмы в пути это хорошо понимается и хорошо изучается (по крайней мере, относительно). Помните:

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

перец пароли, безусловно, хорошая вещь, чтобы сделать, но давайте посмотрим, почему.

Сначала мы должны ответить на вопрос, когда именно перец помогает. Перец защищает только пароли, пока он остается секретным, поэтому, если злоумышленник имеет доступ к самому серверу, он бесполезен. Гораздо проще атака, хотя это SQL-инъекция, которая позволяет читать доступ к базе данных (к нашим хэш-значениям), я подготовил демонстрация SQL-инъекции чтобы показать, как легко это может быть (нажмите следующая стрелка, чтобы получить готовый ввод).

тогда что же перец на самом деле помогает? Пока перец остается секретным, он защищает слабые пароли от атаки словаря. Пароль 1234 тогда станет что-то вроде 1234-p*deDIUZeRweretWy+.O. Этот пароль не только намного длиннее, он также содержит специальные символы и никогда не будет частью любого словаря.

теперь мы можем оценить, какие пароли будут использовать наши пользователи, вероятно, больше пользователей будут вводить слабые пароли, так как есть пользователи с паролями между 64-72 символов (на самом деле это будет очень редко).

еще один момент-это диапазон для перебора. Хэш-функция sha256 вернет 256 бит вывода или 1. 2e77 комбинаций, это слишком много для грубой силы, даже для GPU (если я правильно рассчитал, для этого потребуется около 2E61 лет на GPU в 2013 году). Таким образом, мы не получаем реальный недостаток применения перца. Поскольку хэш-значения не являются систематическими, вы не можете ускорить грубое принуждение с общими закономерностями.

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

P. P. S Я думаю, что ваш пример ошибочен, вы не можете сгенерировать хэш с полной длиной пароля и проверить его усеченным. Вероятно, вы хотели применить перец таким же образом для генерации хэша и для проверки хэша.

Bcrypt использует алгоритм, основанный на дорогостоящем алгоритме настройки ключа Blowfish.

рекомендуемый предел пароля 56 байт (включая нулевой байт завершения) для bcrypt относится к 448-битному пределу ключа Blowfish. Любые байты за пределами этого предела не полностью смешиваются в результирующий хэш. Таким образом, 72-байтовый абсолютный предел для паролей bcrypt менее релевантен, если учесть фактическое влияние на результирующий хэш этих байтов.

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

конечно, в случае, если таблица паролей не нарушается, мы должны позволить хакерам только, самое большее, десять попыток угадать пароль пользователя 55 байт, прежде чем заблокировать учетную запись пользователя;)

Если вы решите предварительно хэшировать пароль длиной более 55 байт, то вам следует использовать SHA-384, так как он имеет самый большой выход без идти над пределом.