Как правильно использовать bcrypt для хеширования паролей в PHP?
Всем привет! Я начинающий PHP-разработчик и никак не могу разобраться с безопасным хранением паролей. Сейчас я просто использую функцию md5() или sha1() для хеширования, но где-то прочитал, что это неправильно и небезопасно. Говорят, что нужно использовать bcrypt.
<?php
// Мой текущий код (знаю, что плохо)
$password = 'my_secret_pass';
$hash = md5($password);
// Сохраняю $hash в базу данных
// Проверка при логине
if (md5($_POST['password']) == $hash_from_db) {
echo "Успешный вход!";
}
?>
Я слышал про bcrypt, но не понимаю, как его подключить и использовать. Вроде бы в PHP есть какая-то встроенная функция, но я не знаю, как она называется и как правильно с ней работать. Также меня смущает, что нужно указывать "соль" (salt) — что это такое и где её хранить? Нужно ли генерировать новую соль для каждого пароля? И как потом проверять пароль при входе пользователя?
Подскажите, пожалуйста, пошагово: как правильно хешировать пароль при регистрации и как проверять его при логине. Буду очень благодарен за примеры кода с пояснениями!
<<Правильное хеширование паролей с помощью bcrypt в PHP
Вы абсолютно правы: md5 и sha1 не подходят для хранения паролей, так как они слишком быстрые и уязвимы для атак перебором. Начиная с PHP 5.5, в языке есть встроенная поддержка bcrypt через функции password_hash() и password_verify(). Они автоматически генерируют безопасную соль и используют алгоритм bcrypt.
Вот как должен выглядеть правильный код:
<?php
// ПРИ РЕГИСТРАЦИИ - хешируем пароль
$password = 'my_secret_pass';
$hash = password_hash($password, PASSWORD_BCRYPT);
// Сохраняем $hash в базу данных (в поле VARCHAR(255) или больше)
// ПРИ ЛОГИНЕ - проверяем пароль
$input_password = $_POST['password']; // пароль из формы
$stored_hash = $hash_from_db; // хеш из базы данных
if (password_verify($input_password, $stored_hash)) {
echo "Успешный вход!";
} else {
echo "Неверный пароль!";
}
?>
Что происходит под капотом?
- password_hash() — генерирует случайную соль (salt) длиной 22 символа, объединяет её с паролем и применяет bcrypt. Результат — строка вида
$2y$10$..., где10— это "стоимость" (cost factor), определяющая количество итераций хеширования. - Соль хранится прямо внутри хеша — вам не нужно хранить её отдельно! Функция
password_verify()сама извлекает соль из сохранённого хеша и использует её для проверки. - PASSWORD_BCRYPT — константа, указывающая на алгоритм bcrypt. Можно также использовать
PASSWORD_DEFAULT(рекомендуется) — PHP будет использовать самый безопасный алгоритм на текущий момент (сейчас это bcrypt, в будущем может стать argon2).
Настройка стоимости (cost factor)
По умолчанию стоимость равна 10. Это значит, что bcrypt выполнит 2^10 = 1024 итерации. Вы можете увеличить это значение для повышения безопасности (но учтите, что это замедлит работу сервера). Рекомендуется выбирать такое значение, чтобы хеширование занимало около 0.1-0.5 секунды на вашем железе:
<?php
$options = [
'cost' => 12, // 2^12 = 4096 итераций
];
$hash = password_hash($password, PASSWORD_BCRYPT, $options);
?>
Важные моменты
- Храните хеш в поле базы данных типа VARCHAR(255) или TEXT. Длина хеша bcrypt — 60 символов, но лучше дать запас на будущее.
- Никогда не обрезайте хеш! Он должен сохраняться целиком.
- Для проверки не нужно повторно вызывать
password_hash()— толькоpassword_verify(). - Если ваша версия PHP ниже 5.5, используйте библиотеку
password_compat(это полифилл от авторов PHP).
Теперь ваш код безопасен! Даже если злоумышленник получит доступ к базе данных, он не сможет восстановить исходные пароли за разумное время благодаря bcrypt.
<<Альтернативный подход: использование Argon2 (ещё безопаснее)
Начиная с PHP 7.2, появилась поддержка алгоритма Argon2, который считается более современным и безопасным, чем bcrypt. Он устойчив к атакам на GPU и ASIC-ускорители. Используется он почти так же просто:
<?php
// Хеширование с Argon2i (рекомендуется для защиты от side-channel атак)
$hash = password_hash($password, PASSWORD_ARGON2I);
// Или Argon2id (ещё лучше, если доступен в PHP 7.3+)
$hash = password_hash($password, PASSWORD_ARGON2ID);
// Проверка — абсолютно так же, как с bcrypt
if (password_verify($input_password, $hash)) {
echo "Верный пароль!";
}
?>
Дополнительные настройки для Argon2
Вы можете настроить три параметра: memory_cost (память в килобайтах), time_cost (количество итераций) и threads (количество потоков):
<?php
$options = [
'memory_cost' => 1 << 17, // 128 MB
'time_cost' => 4,
'threads' => 2,
];
$hash = password_hash($password, PASSWORD_ARGON2ID, $options);
?>
Какой алгоритм выбрать? Если ваш PHP 7.2+, используйте PASSWORD_ARGON2ID — это золотой стандарт на 2024 год. Если нужна максимальная совместимость со старыми версиями — оставайтесь на PASSWORD_BCRYPT. Главное — никогда не используйте md5/sha1/crypt() с ручной солью. Доверяйте встроенным функциям PHP!