Формат выходной строки: алгоритм, соль и хеш через разделитель

При работе с библиотекой password-hash в JavaScript результатом хеширования пароля становится строка фиксированного формата, предназначенная для хранения и последующей проверки. Основная идея заключается в объединении всех критически важных параметров в одной строке, чтобы обеспечить воспроизводимость проверки и исключить необходимость хранения отдельных полей в базе данных.


Структура выходной строки

Выходная строка формируется по схеме:

algorithm:iterations:salt:hash

или в более упрощённом варианте, если количество итераций фиксировано:

algorithm:salt:hash

Каждый элемент имеет строго определённое назначение:

algorithm — идентификатор алгоритма хеширования iterations — число итераций (если используется PBKDF2 или аналогичный алгоритм) salt — криптографическая соль hash — итоговый хеш пароля

Разделителем выступает двоеточие :. В некоторых реализациях допускается альтернативный разделитель (например, $), но в контексте данной библиотеки стандартом считается именно :.


Назначение алгоритма в строке

Поле algorithm необходимо для обеспечения обратной совместимости. Даже если система в будущем перейдёт на более стойкий алгоритм, старые записи останутся валидными.

Примеры значений:

  • pbkdf2
  • argon2id
  • bcrypt

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


Итерации как фактор стоимости

Поле iterations определяет вычислительную сложность алгоритма.

Пример:

pbkdf2:100000:...

Чем выше значение, тем:

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

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


Соль как элемент уникальности

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

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

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

Пример:

pbkdf2:100000:Qx7m9Pz8aL...:...

Хеш как итоговое значение

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

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

  • не должно быть обратимо
  • зависит от всех предыдущих параметров
  • может быть представлено в Base64 или Hex

Пример итоговой строки:

pbkdf2:100000:Qx7m9Pz8aL:8f3a91c4d9b7e2a1f0c6

Причины использования единой строки

Объединение всех параметров в одной строке решает несколько задач:

  1. Упрощение хранения Достаточно одного поля в базе данных вместо нескольких колонок.

  2. Самодостаточность данных Каждая строка содержит всё необходимое для проверки пароля.

  3. Гибкость обновлений алгоритмов Можно менять алгоритм без миграции старых записей.

  4. Совместимость версий Разные версии системы могут корректно обрабатывать один и тот же формат.


Разбор строки при проверке пароля

Процесс проверки включает разбиение строки на компоненты:

const [algorithm, iterations, salt, hash] = stored.split(':');

Далее выполняется повторное хеширование введённого пароля с использованием извлечённых параметров. Полученный результат сравнивается с сохранённым hash.

Важно учитывать, что сравнение должно выполняться в константное время для защиты от timing-атак.


Особенности кодирования соли и хеша

При использовании бинарных данных возникает необходимость кодирования:

  • Base64 чаще используется для компактности
  • Hex — для простоты отладки

Пример Base64-формата:

argon2id:3:U2FsdFN0cmluZw==:bXlIYXNoVmFsdWU=

При этом важно соблюдать единый стандарт кодирования внутри системы.


Ограничения формата

Несмотря на универсальность, строковый формат имеет ограничения:

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

Для решения этих проблем иногда вводят версионность формата:

v1:pbkdf2:100000:salt:hash

Версионирование структуры

Добавление версии позволяет изменять формат без потери совместимости.

Пример расширенного формата:

v2:argon2id:3:Qx7m9Pz8aL:8f3a91c4d9b7e2a1f0c6

Поле версии:

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

Обработка ошибок при разборе

При парсинге строки необходимо учитывать:

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

Пример базовой проверки:

if (parts.length < 4) {
  throw new Error('Invalid hash format');
}

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

Структура algorithm:salt:hash является компромиссом между:

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

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