Как использовать алгоритм Argon2 с password_hash?
Итак, я слышал, что PHP 7.2 представил новый алгоритм Argon2. Но я запутался в том, как я могу использовать его с моим существующим кодом. Например, у меня есть это
$password = password_hash('somepassword', PASSWORD_DEFAULT, ['cost' => 12]);
Есть ли PASSWORD_DEFAULT
теперь использовать Argon2? Что, если что, мне нужно изменить с password_verify
? Считается ли сейчас bcrypt небезопасным?
1 ответ
Что такое Argon2? Bcrypt плохо сейчас?
До PHP 7.2 единственный алгоритм хеширования password_hash
использовал был bcrypt. На момент написания статьи bcrypt по-прежнему считается сильным хэшем, особенно по сравнению с его предшественниками, md5
а также sha1
(оба из которых небезопасны, потому что они быстры). Argon2 - просто более дорогой алгоритм грубой силы
Argon2i использует независимый от данных доступ к памяти. Это медленнее, потому что он делает больше проходов по памяти, чтобы защитить от атак компромисс. Настоятельно рекомендуется для хеширования паролей и получения ключей на основе паролей.
Bcrypt по-прежнему является приемлемым хешем для паролей. Нет необходимости переключаться, если вы не хотите (с версии 7.2.0). Также, PASSWORD_DEFAULT
должен изменяться только (в соответствии с политикой PHP Internals) в следующей полной версии (7.3.0 или выше). Если вы хотите, чтобы вы продолжали использовать только bcrypt, вы можете использовать PASSWORD_BCRYPT
вместо. Однако в этом нет необходимости, о чем мы поговорим ниже.
Как вы используете Argon2?
Сначала мы переключим второй аргумент password_hash
к одному из них постоянным
PASSWORD_ARGON2I
- PHP 7.2.0+PASSWORD_ARGON2ID
- PHP 7.3.0+ (желательно, если доступно, см. Примечания ниже)
и тогда нам нужно будет изменить наши параметры. bcrypt использует cost
в качестве параметра, сколько раз он перебирает пароль (более высокая стоимость = более длительное время хеширования). Однако существуют разные факторы стоимости
password_hash('somepassword', PASSWORD_ARGON2I, ['memory_cost' => 2048, 'time_cost' => 4, 'threads' => 3]);
Из руководства мы видим, что делают эти опции
memory_cost
- Максимальный объем памяти (в байтах), который можно использовать для вычисления хэша Argon2 (по умолчанию 1024)time_cost
- Максимальное время, которое может потребоваться для вычисления хэша Argon2 (по умолчанию 2)threads
- Количество потоков, используемых для вычисления хэша Argon2 (по умолчанию 2)
Прежде чем изменять их, поймите, что более высокая стоимость замедлит ваш сценарий. Вы хотите запустить тест на своем сервере, чтобы найти параметр, который лучше всего подходит для вас. Обычно это происходит за счет нескольких итераций определенной стоимости. Руководство по PHP дает пример этого, если вам нужно.
Также обратите внимание, что, хотя bcrypt хранит 60 символов, для Argon2 может потребоваться больше. В идеале вы должны сделать так, чтобы в вашем поле пароля было 255 символов.
Что мы меняем в password_verify
?
Ответ здесь... ничего. Понять это password_verify
достаточно умен, чтобы выяснить, какой алгоритм использовался и обрабатывать его соответствующим образом. Как уже упоминалось выше, это означает, что если вы используете PASSWORD_DEFAULT
значение по умолчанию может измениться и не повлиять на вас отрицательно (хотя вам может потребоваться настроить параметры стоимости). password_verify
просто требует алгоритм, который он поддерживает. Если вы переключитесь с bcrypt на Argon2, оба будут проверять одинаково, так как все необходимые данные (соль, хеш и стоимость) хранятся для вас.
//Works for both bcrypt and Argon2
if(password_verify($user_password, $stored_hash)) {
// password validated
}
Если вы хотите обновить хэши из bcrypt, вы можете сделать это, когда пользователь успешно войдет в систему (и, таким образом, предоставит вам хешированный пароль). Просто проверьте, начинается ли ваш хэш $2y$
(маркер bcrypt). Если это так, передайте предоставленный пароль password_hash
снова, но с аргументами Argon2 и сохраните его в поле пароля вошедшего в систему пользователя.
Что такое Argon2ID?
Представленный в PHP 7.3, Argon2ID вносит некоторые улучшения по сравнению с Argon2I, как отмечено в этом вопросе Crypto.SE.
Лучшая компромиссная атака для 1-проходного Argon2id - это комбинированная атака с малым объемом памяти (для первой половины памяти) и ранжирующая атака (для второй половины), которые объединяют фактор около 2,1.
Argon2ID работает с теми же аргументами, что и Argon2I.
Только если вы используете PHP 7.3: я создал две простые и тонкие функции для использования Argon2ID с PHP:
function argon2idHash($plaintext, $password, $encoding = null) {
$plaintextsecured = hash_hmac("sha256", $plaintext, $password);
return $encoding == "hex" ? bin2hex(password_hash($plaintextsecured, PASSWORD_ARGON2ID)) : ($encoding == "base64" ? base64_encode(password_hash($plaintextsecured, PASSWORD_ARGON2ID)) : password_hash($plaintextsecured, PASSWORD_ARGON2ID));
}
function argon2idHashVerify($plaintext, $password, $hash, $encoding = null) {
$plaintextsecured = hash_hmac("sha256", $plaintext, $password);
return password_verify($plaintextsecured, $encoding == "hex" ? hex2bin($hash) : ($encoding == "base64" ? base64_decode($hash) : $hash)) ? true : false;
}
Чтобы получить хешированное значение, используйте (последний параметр не обязателен, вы можете выбрать шестнадцатеричный, base64 или ничего) [return => string]:
$salt = "LALALA";
argon2idHash($clearvalue, $salt, "hex"); // with encoding
argon2idHash($clearvalue, $salt); // without encoding
Для проверки использования хешированного значения (параметр $salt должен соответствовать солевому, установленному во время хеширования, то же правило применяется к кодированию, если оно используется) [return => bool]:
$salt = "LALALA";
argon2idHashVerify($clearvalue, $salt, $hashtoverify, "hex") ? "match" : "dont match"; // with encoding
argon2idHashVerify($clearvalue, $salt, $hashtoverify) ? "match" : "dont match"; // without encoding
Наконец, если вы знаете PHP, вы можете изменять эти функции по своему вкусу, но на данный момент это лучший из известных мне способов безопасного хранения паролей в базах данных.