Что такое соль и почему она меняет всё

Соль — это случайная строка данных, добавляемая к паролю перед его хешированием. Она не является секретной и хранится вместе с хешем. Основная задача соли — сделать каждый результат хеширования уникальным, даже если исходные пароли совпадают.

Формально процесс выглядит так:

hash = H(password + salt)

где H — криптографическая хеш-функция.

В библиотеке bcrypt.js соль является встроенной частью алгоритма и используется автоматически, что избавляет от необходимости реализовывать её вручную.


Почему одинаковые пароли должны давать разные хеши

Без использования соли один и тот же пароль всегда даёт одинаковый хеш. Это приводит к ряду критических уязвимостей:

  • возможность обнаружить пользователей с одинаковыми паролями
  • упрощение атак с использованием предварительно вычисленных таблиц (rainbow tables)
  • массовое взлом паролей при компрометации базы данных

Соль устраняет эти проблемы. Даже если два пользователя выбрали пароль 123456, их хеши будут различаться из-за разных значений соли.


Встроенная соль в bcrypt.js

Алгоритм bcrypt изначально спроектирован с поддержкой соли. В bcrypt.js при вызове функции хеширования:

const bcrypt = require('bcryptjs');

const hash = bcrypt.hashSync('password123', 10);

происходит следующее:

  1. Генерируется случайная соль
  2. Соль комбинируется с паролем
  3. Выполняется многократное хеширование (cost factor)
  4. Результат сохраняется в единой строке

Итоговый хеш содержит:

  • версию алгоритма
  • стоимость (cost factor)
  • соль
  • сам хеш

Пример:

$2a$10$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36L7eFhK2X9z8cJ9b0q9K9a

Разбор:

  • $2a$ — версия bcrypt
  • 10 — cost factor (сложность)
  • EixZaYVK1fsbw1ZfbX3OXe — соль
  • остальная часть — хеш

Генерация соли

Соль создаётся с помощью криптографически стойкого генератора случайных чисел. В bcrypt.js можно явно управлять этим процессом:

const salt = bcrypt.genSaltSync(10);
const hash = bcrypt.hashSync('password123', salt);

Параметр 10 определяет сложность (количество раундов), а не длину соли.

Важно:

  • соль должна быть уникальной для каждого пароля
  • использование предсказуемых или повторяющихся значений недопустимо

Как соль защищает от rainbow table атак

Rainbow tables — это заранее вычисленные таблицы соответствий между паролями и их хешами.

Без соли:

password → 5f4dcc3b5aa765d61d8327deb882cf99

С солью:

password + salt1 → hash1
password + salt2 → hash2

Атакующему пришлось бы создавать отдельную таблицу для каждой возможной соли, что делает атаку практически невозможной.


Проверка пароля и роль соли

При проверке пароля соль не передаётся отдельно. Она уже встроена в хеш:

const isMatch = bcrypt.compareSync('password123', hash);

Процесс:

  1. Из хеша извлекается соль
  2. Введённый пароль комбинируется с этой солью
  3. Выполняется хеширование
  4. Сравниваются результаты

Это означает:

  • разработчику не нужно хранить соль отдельно
  • алгоритм полностью самодостаточен

Ошибки при работе с солью

1. Повторное использование соли Использование одной и той же соли для всех пользователей сводит защиту к минимуму.

2. Ручная реализация соли Попытки самостоятельно добавлять соль поверх bcrypt избыточны и могут привести к ошибкам.

3. Хранение соли отдельно В bcrypt соль уже включена в итоговую строку. Дополнительное хранение усложняет систему без пользы.


Влияние соли на безопасность системы

Соль кардинально меняет модель угроз:

Без соли С солью
Одинаковые пароли → одинаковые хеши Каждый хеш уникален
Уязвимость к rainbow tables Защита от предвычисленных атак
Быстрое массовое взлом Требуется индивидуальная атака
Утечка базы = мгновенный риск Утечка требует значительных вычислений

Связь соли и cost factor

Соль и cost factor работают совместно:

  • Соль защищает от предвычисленных атак
  • Cost factor замедляет перебор

В bcrypt:

bcrypt.hashSync(password, 12);

где 12 означает 2¹² итераций.

Даже если злоумышленник знает соль:

  • ему приходится перебирать каждый пароль отдельно
  • каждый шаг вычислительно дорогой

Практическое значение

Соль превращает хеширование из простой функции в устойчивый к атакам механизм хранения паролей. Без неё даже сильный алгоритм может оказаться уязвимым.

В контексте bcrypt.js соль:

  • генерируется автоматически
  • безопасно встраивается в результат
  • прозрачно используется при проверке

Это позволяет сосредоточиться на логике приложения, не реализуя криптографию вручную.