Как создавать и хранить хэши паролей с помощью Blowfish в PHP

1) Как вы создаете безопасные хэши паролей Blowfish с помощью crypt()?

$hash = crypt('somePassword', '$2a$07$nGYCCmhrzjrgdcxjH$');

1a) Каково значение «$2a»? Указывает ли это только на то, что следует использовать алгоритм Blowfish?
1b) Каково значение "$07"? Означает ли более высокое значение более безопасный хэш?
1c) Каково значение "$nGYCCmhrzjrgdcxjH$"? Это соль, которая будет использоваться? Должно ли это генерироваться случайным образом? Жестко запрограммировано?

2) Как вы храните хэши Blowfish?

echo $hash;
//Output: $2a$07$nGYCCmhrzjrgdcxjH$$$$.xLJMTJxaRa12DnhpAJmKQw.NXXZHgyq

2a) Какая часть этого должна храниться в базе данных?
2b) Какой тип данных следует использовать для столбца (MySQL)?

3) Как проверить попытку входа в систему?


person Community    schedule 13.02.2011    source источник
comment
1.) Прочитайте руководство 2. и 3. вопросы для самих себя.   -  person Linus Kleen    schedule 13.02.2011
comment
См. также фреймворк хеширования паролей PHP (PHPass) Openwall. Он портативный и защищен от ряда распространенных атак на пароли пользователей. Парень, который написал фреймворк (SolarDesigner), — это тот же парень, который написал John The Ripper. Так что он кое-что знает об атаках на пароли.   -  person jww    schedule 12.10.2014


Ответы (2)


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

Для получения дополнительной информации см. http://www.openwall.com/articles/PHP-Users-Passwords — я рекомендую использовать библиотеку phpass, потому что она генерирует для вас случайную соль, в отличие от crypt().

person xyphoid    schedule 13.02.2011
comment
chargen.matasano.com/chargen/2007/9/7/ — еще один отличный ресурс. - person TML; 14.02.2011
comment
Вместо PHPass я более склонен использовать встроенные функции, предоставляемые PHP. Из того, что я прочитал, я считаю, что PHP автоматически генерирует соль при использовании функции password_hash() If omitted, a random salt will be generated by password_hash() for each password hashed. This is the intended mode of operation. uk1.php.net/ пароль_хэш - person Luke; 24.02.2014
comment
Да, с тех пор, как был написан этот пост, PHP добавил password_hash — теперь это лучший вариант, чем phpass. - person xyphoid; 25.02.2014

1а) Стойкость шифрования - требование в пределах 4..31. См. http://php.net/manual/en/function.crypt.php

1б) См. 1а

1с) См. 1а. «соль» не должна быть случайной, иначе вы не сможете регенерировать тот же хеш для заданного ввода — см. 3.

2а) Строго говоря, все, кроме хэша (на случай компрометации БД). Кроме того, сохраните свою соль в файле, недоступном в корне документа веб-сервера, и включите его. Установите для него максимально строгие разрешения; в идеале только чтение для службы веб-хостинга (например, apache), без прав на запись или выполнение. Строго говоря, зависит от того, насколько вы хотите защищаться от хакеров. Отсутствие хранения соли только усложняет жизнь; им по-прежнему нужно правильно обрабатывать данные, вводимые в алгоритм, но зачем упрощать?

2b) VARCHAR(32) должен подойти для иглобрюха, если не хранить хэш

3) Предполагая, что вы уже запустили надлежащий код предотвращения инъекций и т. д., поэтому, пожалуйста, не просто копируйте нижеприведенное вслепую (и в идеале используйте PDO вместо расширения mysql). Приведенное ниже относится к Blowfish, SHA-256 и SHA-512, которые возвращают соль в хеше. Потребуется модификация для других алгоритмов...

//store this in another file outside web directory and include it
$salt = '$2a$07$somevalidbutrandomchars$'

...

//combine username + password to give algorithm more chars to work with
$password_hash = crypt($valid_username . $valid_password, $salt)

//Anything less than 13 chars is a failure (see manual)
if (strlen($password_hash) < 13 || $password_hash == $salt)
then die('Invalid blowfish result');

//Drop the salt from beginning of the hash result. 
//Note, irrespective of number of chars provided, algorithm will always 
//use the number defined in constant CRYPT_SALT_LENGTH
$trimmed_password_hash = substring($password_hash, CRYPT_SALT_LENGTH);
mysql_query("INSERT INTO `users` (username,p assword_hash) VALUES '$valid_username', '$trimmed_password_hash'");

...

$dbRes = mysql_query("SELECT password_hash FROM `users` WHERE username = '$user_input_username' LIMIT 1");
//re-apply salt to output of database and re-run algorithm testing for match
if (substring($salt, CRYPT_SALT_LENGTH) . mysql_result($dbRes, 0, 'password_hash') ) ===
        crypt($user_input_username . $user_input_password, $salt) ) {
    //... do stuff for validated user
}
person Matt    schedule 13.02.2011
comment
Обратите внимание, что вышеуказанное не следует использовать для входа в систему для защиты конфиденциальных данных. Для этого, как минимум, используйте разные соли для каждого пользователя и храните значение соли в отдельной базе данных (доступной только другому пользователю MySQL) с таблицей, отображающей имя пользователя на соль. - person Matt; 13.02.2011
comment
Мой CRYPT_SALT_LENGTH равен 123, поэтому ваша строка substr() возвращает пустую строку. Что случилось с этим? - person ; 13.02.2011
comment
Я использовал $hash = substr($hash, strlen($salt)); или $hash = str_replace($salt, '', $hash);. (Они возвращаются тем же.) Кажется, работает. Кажется, что окончательный хеш иглобрюха состоит из 20 букв, поэтому CHAR (20) может быть подходящим типом данных? - person ; 13.02.2011
comment
Ответ выше просто неверен. В crypt() вы сохраняете весь результат crypt() и возвращаете его себе позже для проверки... - person TML; 14.02.2011
comment
@TML, верно - этот ответ - плохой совет. Соль должна быть уникальной для каждого хэша и автоматически сохраняется как суффикс хэша crypt(). - person Xeoncross; 17.04.2012
comment
Иметь фиксированную соль — плохая идея. Вся цель соли состоит в том, чтобы добавить случайные биты к паролю, который можно угадать (например, 12345678). Вероятность успешной атаки на сохраненные пароли с фиксированной солью выше. - person rjha94; 30.04.2012
comment
В чем причина использования случайной соли для каждого crypt(), если вы собираетесь хранить эту соль в базе данных как часть зашифрованного пароля? Если безопасность вашей базы данных скомпрометирована, а злоумышленник имеет доступ к этой таблице и может прочитать зашифрованные поля пароля, то у него будет прямой доступ к вашей сверхсекретной и случайно сгенерированной соли. Хотя каждый раз случайная соль может заставить ваш crypt() работать каждый раз по-разному, ваша безопасность не будет повышена. - person Neven Boyanov; 29.11.2012
comment
Мой комментарий выше не совсем корректен. Хранение соли вместе с хэшем защитит вас от поиска по радужным таблицам, потому что для одного и того же пароля будут разные хэши, но это не защитит вас от грубой силы или словарей паролей. Пример: если у меня есть доступ ко всем солям и хэшам, я смогу проверить, у кого есть пароль «тест» или «1234» и т. д. — не правда ли? - person Neven Boyanov; 29.11.2012