Безопасное хеширование и соль для паролей в PHP
Правильное решение: используйте встроенные функции PHP
Вы на верном пути, отказываясь от MD5. Современный PHP предоставляет готовые и безопасные инструменты для хеширования паролей. Забудьте про самостоятельное создание соли — PHP сделает это за вас автоматически и криптографически правильно.
Основные функции
password_hash()— создаёт хеш пароля с автоматической генерацией солиpassword_verify()— проверяет пароль против хешаpassword_needs_rehash()— проверяет, нужно ли обновить хеш (полезно при смене алгоритма)
Пример правильной реализации
<?php
// Регистрация пользователя
function registerUser($password) {
// PASSWORD_BCRYPT использует алгоритм bcrypt (по умолчанию)
// 'cost' — параметр, влияющий на вычислительную сложность (по умолчанию 10)
$hash = password_hash($password, PASSWORD_BCRYPT, ['cost' => 12]);
// Сохраняем $hash в базу данных (всё вместе: алгоритм, соль, хеш)
return $hash;
}
// Авторизация пользователя
function loginUser($password, $hashFromDatabase) {
// password_verify извлекает соль из хеша и проверяет пароль
if (password_verify($password, $hashFromDatabase)) {
return "Пароль верный!";
} else {
return "Неверный пароль!";
}
}
// Пример использования
$hash = registerUser('my_secure_password');
echo $hash; // Вывод: $2y$12$... (длинная строка, содержащая всё необходимое)
$result = loginUser('my_secure_password', $hash);
echo $result; // "Пароль верный!"
?>
Почему это безопасно?
- Автоматическая соль: Каждый хеш содержит уникальную, криптостойкую соль (22 символа base64). Соль хранится прямо в строке хеша, вам не нужно хранить её отдельно.
- bcrypt: Использует алгоритм Blowfish, который специально разработан медленным для защиты от перебора. Даже с мощным GPU перебор bcrypt-хешей крайне неэффективен.
- Радужные таблицы: Бесполезны, так как соль уникальна для каждого пароля.
- Параметр cost: Увеличивает время вычисления хеша. Значение 12 делает его примерно в 4 раза медленнее, чем значение по умолчанию 10. Это замедляет атаки перебором.
Что ещё нужно знать?
Если вы обновляете PHP или меняете алгоритм (например, на Argon2), используйте password_needs_rehash():
<?php
// При каждом входе пользователя проверяем, нужно ли обновить хеш
if (password_needs_rehash($hashFromDatabase, PASSWORD_BCRYPT, ['cost' => 12])) {
$newHash = password_hash($password, PASSWORD_BCRYPT, ['cost' => 12]);
// Сохраняем $newHash в базу данных
}
?>
Важно: Никогда не используйте md5(), sha1() или sha256() для паролей. Они слишком быстрые и уязвимы к перебору. Только password_hash() с bcrypt или Argon2 (начиная с PHP 7.2).
Альтернатива: Argon2 (рекомендуется для PHP 7.2+)
Если ваш сервер использует PHP 7.2 или новее, рассмотрите алгоритм Argon2. Он был признан победителем конкурса Password Hashing Competition и считается более безопасным, чем bcrypt. Использование почти идентично:
<?php
// Argon2i — защищён от side-channel атак
$hash = password_hash($password, PASSWORD_ARGON2I, [
'memory_cost' => 1024, // 1 MB памяти
'time_cost' => 2, // 2 итерации
'threads' => 2 // 2 потока (только для Argon2id)
]);
// Argon2id — комбинирует защиту от side-channel и GPU (рекомендуется)
$hash = password_hash($password, PASSWORD_ARGON2ID, [
'memory_cost' => 2048, // 2 MB
'time_cost' => 3,
'threads' => 2
]);
// Проверка остаётся такой же
if (password_verify($password, $hash)) {
echo "Пароль верный!";
}
?>
Преимущества Argon2 перед bcrypt:
- Устойчив к атакам на GPU (нужна большая память, что снижает параллелизацию)
- Настраиваемые параметры: память, время, потоки
- Лучшая защита от ASIC-майнеров
Совет: Используйте PASSWORD_ARGON2ID (доступен с PHP 8.1) — он сочетает защиту от side-channel атак (как Argon2i) и от GPU (как Argon2d). Если не уверены, начните с bcrypt — он проверен годами и безопасен при правильной настройке cost.