Соль — это случайная строка, которую добавляют к паролю перед хешированием. Её хранят в базе данных рядом с хешем. Соль не секрет, её задача — сделать каждый хеш уникальным, даже если пароли у пользователей совпадают.
Почему без соли небезопасно
Хеш-функция детерминирована: на одинаковый вход она всегда даёт одинаковый выход. Если хранить просто хеш пароля, возникают две проблемы.
Проблема 1: одинаковые пароли → одинаковые хеши.
Если у 100 пользователей пароль 123456, в базе будет 100 одинаковых хешей. Злоумышленнику достаточно взломать один хеш — и он получит доступ ко всем этим аккаунтам.
Проблема 2: радужные таблицы.
Это заранее подготовленные базы, где для миллионов популярных паролей уже посчитаны хеши. Получив дамп базы, атакующий просто ищет совпадения в такой таблице и быстро восстанавливает пароли.
Соль устраняет обе проблемы: она делает входные данные для хеша уникальными для каждого пользователя.
Как это работает на практике
Схема простая:
- При регистрации генерируют случайную соль.
- Пароль объединяют с солью.
- Полученную строку хешируют.
- В базу сохраняют соль и хеш (пароль не хранят).
- При входе берут сохранённую соль, соединяют с введённым паролем, хешируют и сравнивают с сохранённым хешем.
Пример на PHP (современный подход)
Для хранения паролей не используют «соль вручную» с простыми алгоритмами вроде MD5 или SHA‑256. Вместо этого применяют встроенные функции, которые сами генерируют и используют соль.
// Регистрация: создание хеша $password = 'my_secret_password'; $hash = password_hash($password, PASSWORD_DEFAULT); // $hash содержит алгоритм, соль и сам хеш в одной строке // Пример значения $hash: $2y$10$XY12ab... (дальше длинная строка) // Сохраняем в БД только $hash $stmt = $pdo->prepare('INSERT INTO users (email, password_hash) VALUES (?, ?)'); $stmt->execute([$email, $hash]);
// Вход: проверка пароля $inputPassword = $_POST['password']; $storedHash = $row['password_hash']; // взяли из БД if (password_verify($inputPassword, $storedHash)) { // пароль верный, пускаем пользователя } else { // неверный пароль }
Здесь соль не передаётся отдельно: password_hash сам создаёт криптографически стойкую соль, а password_verify извлекает её из строки хеша и использует для проверки. Это правильный способ для PHP 7.4 и новее.
Что будет, если делать «соль вручную» неправильно
Частая ошибка — брать одну общую соль для всех пользователей и хранить её в коде.
// ПЛОХОЙ ПРИМЕР (не используйте) $globalSalt = 'fixed_salt_string'; $hash = hash('sha256', $password . $globalSalt);
Минусы такого подхода:
- У пользователей с одинаковым паролем будут одинаковые хеши.
- Если злоумышленник узнает общую соль (например, из кода), он сможет подготовить радужную таблицу именно под эту соль и быстро взломать все хеши.
Ещё хуже — вообще не использовать соль:
// ОЧЕНЬ ПЛОХО (не используйте) $hash = hash('sha256', $password);
В этом случае любой популярный пароль мгновенно находится по радужным таблицам.
Важные нюансы
- Соль не должна быть секретной. Её хранят прямо в базе рядом с хешем. Секретность соли не даёт дополнительной защиты; её ценность — в уникальности для каждого пользователя и достаточной длине.
- Длина и качество соли. Соль должна генерироваться криптографически стойким генератором случайных чисел. Встроенные функции вроде
password_hashделают это правильно. - Не изобретайте свои схемы. Для хранения паролей используйте стандартные функции:
password_hash/password_verifyв PHP,bcrypt/argon2в других языках. Они уже учитывают соль, количество итераций и другие параметры безопасности.
Ещё один пример: сравнение «без соли» и «с солью»
Допустим, два пользователя выбрали пароль qwerty.
Без соли (хеш SHA‑256):
- Пользователь 1:
hash('sha256', 'qwerty')→d8578edf8458ce06fbc5bb76a58c51b3... - Пользователь 2:
hash('sha256', 'qwerty')→ тот же самый хеш.
По хешам видно, что пароли совпадают. Взломав один, атакующий получает оба аккаунта.
С солью (через password_hash):
- Пользователь 1: хеш будет, например,
$2y$10$a1b2c3d4e5f6g7h8i9j0k1... - Пользователь 2: хеш будет совсем другим, например
$2y$10$z9y8x7w6v5u4t3s2r1q0p9...
Даже при одинаковом пароле хеши разные, потому что внутри них — разные соли. По хешам нельзя понять, что пароли совпали.
Практический вывод
- Соль нужна, чтобы одинаковые пароли давали разные хеши и чтобы сделать радужные таблицы практически бесполезными.
- В современных проектах не подбирают соль вручную и не склеивают её с паролем в коде. Используют готовые функции типа
password_hash. - В базе хранят только хеш (в котором уже «зашита» соль) и, при необходимости, отдельно — саму соль как часть формата хеша (но в случае
password_hashэто единая строка).
