Хранение хеша в базе данных: правила и ошибки

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


Структура поля для хранения

Хеш, получаемый в JavaScript при использовании библиотек уровня password-hash, bcrypt или argon2, представляет собой строку переменной длины, содержащую:

  • алгоритм хеширования
  • параметры сложности (cost factor, iterations)
  • соль
  • сам хеш

Рекомендуемые типы полей

В реляционных базах данных чаще всего используются:

  • VARCHAR(255) — универсальный вариант для большинства современных алгоритмов
  • TEXT — при использовании алгоритмов с длинными выходными значениями (например, Argon2id с расширенными параметрами)

Использование фиксированных бинарных типов (BINARY, VARBINARY) возможно, но требует строгого контроля формата сериализации.


Недопустимость хранения необработанного пароля

Хранение исходного пароля в любом виде исключается:

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

Даже кратковременное присутствие пароля в памяти процесса без необходимости увеличивает поверхность атаки.


Форматирование хеша

При использовании JavaScript-библиотек формат строки хеша обычно включает все необходимые компоненты внутри одного значения.

Пример структуры:

$algorithm$parameters$salt$hash

Особенности хранения:

  • вся строка сохраняется целиком без разбиения
  • запрещается ручное отделение salt и hash на уровне базы данных
  • изменение формата нарушает совместимость с проверкой пароля

Соль и её роль в хранении

Современные библиотеки автоматически генерируют соль и включают её в итоговый хеш. Это исключает необходимость отдельного хранения.

Ошибки при проектировании схемы:

  • создание отдельного столбца salt
  • повторное использование одной соли для всех пользователей
  • генерация соли на стороне базы данных

Каждая запись должна иметь уникальную соль, встроенную в хеш.


Использование «перца» (pepper)

Дополнительный секретный параметр, называемый pepper, не хранится в базе данных.

Особенности:

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

Типичная ошибка — сохранение pepper в той же базе данных, что и хеши. В таком случае его защитная функция теряется при утечке.


Индексация и ограничения

Хеш пароля не участвует в поисковых или сортировочных операциях.

Следовательно:

  • индексирование поля хеша не требуется
  • создание уникального индекса бессмысленно
  • сравнение выполняется только в момент аутентификации

Использование индексов увеличивает размер таблицы без практической пользы.


Сравнение хешей

Проверка пароля осуществляется не сравнением строк напрямую, а через функцию проверки библиотеки.

Особенности процесса:

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

Прямое SQL-сравнение исключается как архитектурная ошибка.


Проблемы кодировки и длины

При хранении хешей важно учитывать:

  • использование UTF-8 как стандартной кодировки
  • отсутствие обрезания строки на уровне ORM или драйвера
  • контроль максимальной длины поля

Ошибка усечения строки приводит к невозможности проверки пароля.


Обновление алгоритмов хеширования

Со временем алгоритмы могут устаревать. В таких случаях:

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

Такой подход позволяет постепенно мигрировать систему без принудительного сброса паролей.


Ошибки проектирования схемы хранения

Наиболее распространённые проблемы:

  • использование слабых алгоритмов (MD5, SHA1) для паролей
  • самостоятельная реализация хеширования вместо проверенных библиотек
  • хранение нескольких версий хеша без версии алгоритма в строке
  • логирование значений хеша в диагностических системах
  • передача хеша между сервисами без необходимости

Многосервисная архитектура

В распределённых системах важно учитывать:

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

Несогласованность версий библиотеки password-hash или аналогов приводит к невозможности проверки ранее созданных паролей.


Миграция и совместимость

При изменении алгоритма хранения:

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

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


Утечки и последствия хранения

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

Факторы, влияющие на стойкость:

  • сложность алгоритма (cost factor)
  • длина и энтропия исходного пароля
  • наличие уникальной соли
  • отсутствие дополнительных утечек (логов, резервных копий)

Работа с ORM и абстракциями

При использовании ORM в JavaScript (Sequelize, TypeORM и аналогов):

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

Некорректная конфигурация ORM может привести к повторному хешированию уже хешированного значения.