Хеширование паролей
Чтобы обеспечить безопасность наших пользователей, мы не храним их пароли в читаемом виде, а сохраняем только их отпечаток (так называемый хеш). Из отпечатка невозможно восстановить исходный вид пароля. Важно использовать безопасный алгоритм для создания отпечатка. С этим нам поможет класс Nette\Security\Passwords.
Фреймворк автоматически добавляет в DI-контейнер сервис типа
Nette\Security\Passwords
под именем security.passwords
, к которому вы можете
получить доступ, запросив его передачу с помощью dependency injection.
use Nette\Security\Passwords;
class Foo
{
public function __construct(
private Passwords $passwords,
) {
}
}
__construct ($algo=PASSWORD_DEFAULT, array $options=[])
Выбираем, какой безопасный алгоритм использовать для генерации хеша и конфигурируем его параметры.
По умолчанию используется PASSWORD_DEFAULT
, то есть выбор алгоритма
оставляется на усмотрение PHP. Алгоритм может измениться в новых
версиях PHP, если появятся более новые, более сильные алгоритмы
хеширования. Поэтому вы должны быть осведомлены, что длина
результирующего хеша может измениться, и вы должны хранить его
способом, который может вместить достаточное количество символов,
255 является рекомендуемой шириной.
Пример настройки скорости хеширования алгоритмом bcrypt изменением параметра cost: (в 2020 году по умолчанию 10, хеширование пароля занимает примерно 80 мс, для cost 11 это около 160 мс, для cost 12 примерно 320 мс, чем медленнее, тем лучше защита, при этом скорость 10–12 уже считается достаточной защитой)
// будем хешировать пароли 2^12 (2^cost) итерациями алгоритма bcrypt
$passwords = new Passwords(PASSWORD_BCRYPT, ['cost' => 12]);
С помощью dependency injection:
services:
security.passwords: Nette\Security\Passwords(::PASSWORD_BCRYPT, [cost: 12])
hash (string $passwords): string
Генерирует хеш пароля.
$res = $passwords->hash($password); // Хеширует пароль
Результат $res
— это строка, которая помимо самого хеша
содержит идентификатор использованного алгоритма, его настройки и
криптографическую соль (случайные данные, обеспечивающие, что для
одного и того же пароля будет сгенерирован разный хеш). Таким образом,
он обратно совместим: если, например, вы измените параметры, то и хеши,
сохраненные с использованием предыдущих настроек, можно будет
проверить. Весь этот результат сохраняется в базе данных, поэтому нет
необходимости хранить соль или настройки отдельно.
verify (string $password, string $hash): bool
Проверяет, соответствует ли данный пароль данному отпечатку.
$hash
получите из базы данных по указанному имени пользователя
или адресу электронной почты.
if ($passwords->verify($password, $hash)) {
// правильный пароль
}
needsRehash (string $hash): bool
Проверяет, соответствует ли хеш опциям, указанным в конструкторе.
Полезно использовать в тот момент, когда, например, вы меняете
скорость хеширования. Проверка происходит согласно сохраненным
настройкам, и если needsRehash()
возвращает true
, то необходимо
снова создать хеш, на этот раз с новыми параметрами, и снова сохранить
его в базе данных. Таким образом автоматически “обновляются”
сохраненные хеши при входе пользователей.
if ($passwords->needsRehash($hash)) {
$hash = $passwords->hash($password);
// сохранить $hash в базу данных
}