Avatar ·

Как правильно использовать 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!