Хэши и соль для паролей в PHP: гайд по безопасности 2025

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Пароли под прицелом: почему старые методы больше не работают

Представьте: вы — разработчик, который пишет систему регистрации. Кажется, что может быть проще? Взял пароль, пропустил через md5, сохранил в базу. Но в 2025 году такой подход — прямая дорога к уязвимости. Современные атаки, GPU-брутфорс и радужные таблицы превращают слабые хэши в пыль за секунды. Вопрос из Stack Overflow с тысячами просмотров — «Secure hash and salt for PHP passwords» — не теряет актуальности, и мы разберём его раз и навсегда.

В этой статье вы узнаете, как правильно хэшировать пароли в PHP, используя современные алгоритмы, встроенные функции и соль (salt). Мы адаптируем лучшие ответы сообщества для образовательного контента и покажем, как защитить пользователей даже в 2025 году.

Почему md5 и sha1 — зло

Если вы всё ещё используете md5 или sha1 для хранения паролей — остановитесь. Эти алгоритмы созданы для скорости, а не для безопасности. В 2025 году GPU может подбирать миллиарды md5-хэшей в секунду. Добавление соли (случайной строки) не спасает: радужные таблицы обходятся, но скорость остаётся фатальной.

  • Md5: 2^128 вариантов — взламывается за минуты.
  • Sha1: чуть лучше, но тоже устарел.
  • Соль без замедления: если хэш быстрый, соль лишь откладывает атаку.

Вместо этого нужны алгоритмы с «замедлением» — такие, которые требуют времени и памяти. Именно их использует password_hash.

password_hash и password_verify: встроенное решение от PHP

С PHP 5.5 появились две функции, которые решают 90% проблем с безопасностью паролей: password_hash и password_verify. Они автоматически генерируют криптографически безопасную соль и используют алгоритмы, устойчивые к брутфорсу. В 2025 году это стандарт, и никаких самодельных велосипедов!

Как это работает?

Функция password_hash принимает пароль и алгоритм (по умолчанию — bcrypt, но можно указать argon2). Она возвращает строку, которая уже содержит соль и параметры. Вам не нужно хранить соль отдельно — она внутри хэша.

<?php
// Хэшируем пароль
$password = "SuperSecret123!";
$hash = password_hash($password, PASSWORD_DEFAULT);

echo $hash; // $2y$10$... (60 символов)
?>

Теперь проверим пароль при входе:

<?php
$inputPassword = "SuperSecret123!";
$storedHash = "$2y$10$..."; // из базы данных

if (password_verify($inputPassword, $storedHash)) {
    echo "Пароль верен!";
} else {
    echo "Неверный пароль.";
}
?>

Всё гениально просто. password_verify автоматически извлекает соль из хэша и проверяет пароль. Никаких дополнительных действий.

Выбор алгоритма: bcrypt vs argon2

В 2025 году у вас есть два основных варианта:

  • Bcrypt (PASSWORD_BCRYPT): проверен временем, используется по умолчанию. Устойчив к атакам, но требует настройки cost factor.
  • Argon2 (PASSWORD_ARGON2I или PASSWORD_ARGON2ID): победитель конкурса Password Hashing Competition. Современнее, требует больше памяти, что затрудняет атаки на GPU. Рекомендуется для новых проектов.

Пример с argon2:

<?php
$hash = password_hash($password, PASSWORD_ARGON2ID, [
    'memory_cost' => 1 << 17, // 128 MB
    'time_cost'   => 4,
    'threads'     => 2
]);
?>

Параметр memory_cost — объём памяти в килобайтах. Чем выше, тем безопаснее, но медленнее. Для продакшена тестируйте на своём сервере.

Соль (salt): как она работает и почему не нужна отдельно

Многие новички спрашивают: «Как добавить соль вручную?». Ответ: никак. password_hash генерирует 22 символа случайной соли (для bcrypt) и встраивает её в хэш. Это делает каждый хэш уникальным, даже если пароли одинаковые. Атака по радужным таблицам становится бесполезной.

Если вы всё же хотите добавить свою соль (например, для совместимости со старыми системами), используйте PASSWORD_BCRYPT с опцией salt, но в 2025 году это считается устаревшим. Лучше довериться встроенной генерации.

<?php
// Не делайте так — соль уже внутри!
$customSalt = "myStaticSalt123";
$hash = password_hash($password, PASSWORD_BCRYPT, ['salt' => $customSalt]);
// PHP 7+ выдаст предупреждение, в PHP 8+ опция удалена
?>

Вывод: используйте password_hash без ручной соли — это безопасно и просто.

Лучшие практики 2025: чек-лист для разработчика

На основе обсуждений Stack Overflow и современных рекомендаций, вот что нужно делать:

  • Всегда используйте password_hash и password_verify. Никаких md5, sha1 или собственных функций.
  • Выбирайте PASSWORD_ARGON2ID, если сервер поддерживает PHP 7.2+. Он устойчивее к атакам на GPU.
  • Настраивайте cost factor. Для bcrypt — от 10 до 12 (проверьте время выполнения). Для argon2 — настраивайте memory и time под нагрузку.
  • Не храните пароли в открытом виде. Даже в логах или при отправке на email.
  • Используйте HTTPS. Хэш не спасёт, если пароль перехватят по пути.
  • Проверяйте пароль на сложность. Минимум 8 символов, буквы, цифры, спецсимволы.
  • Обновляйте хэши при входе. Если алгоритм устарел (например, bcrypt сменился на argon2), перехэшируйте пароль при успешном входе.

Пример перехэширования:

<?php
if (password_verify($inputPassword, $storedHash)) {
    if (password_needs_rehash($storedHash, PASSWORD_ARGON2ID)) {
        $newHash = password_hash($inputPassword, PASSWORD_ARGON2ID);
        // Сохраните $newHash в базу данных
    }
    echo "Успешный вход!";
}
?>

Ошибки, которые допускают даже опытные

Даже на Stack Overflow часто встречаются советы, которые могут навредить. Вот

Блоги

Рекомендаций по книгам