Хешування паролів

Щоб забезпечити безпеку наших користувачів, ми не зберігаємо їхні паролі в читабельній формі, а зберігаємо лише відбиток (так званий хеш). З відбитка неможливо відновити початкову форму пароля. Важливо використовувати безпечний алгоритм для створення відбитка. З цим нам допоможе клас 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=[])string

Вибираємо, який безпечний алгоритм для генерації хешу використовувати та конфігуруємо його параметри.

За замовчуванням використовується 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 до бази даних
}
версія: 4.0