Коллизии и их значимость для хеширования паролей

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

Коллизия в контексте хеширования — это ситуация, когда два разных входных значения дают одинаковый хеш-результат. Формально:

  • вход A ≠ вход B
  • но hash(A) = hash(B)

Для обычных хеш-функций общего назначения (например, SHA-1 или MD5) коллизии являются критической проблемой, поскольку они могут использоваться для подмены данных или обхода проверок целостности.

Однако в системах хранения паролей ситуация принципиально отличается: используются не просто хеш-функции, а ключевые деривационные функции (KDF), такие как bcrypt.


Как bcrypt.js работает с хешированием

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

  • встроенная соль (salt)
  • адаптивная вычислительная сложность (cost factor)
  • одностороннее преобразование

Процесс выглядит следующим образом:

  1. Генерируется уникальная соль
  2. Пароль объединяется с солью
  3. Выполняется многократное (итеративное) преобразование
  4. Результат кодируется в строку фиксированного формата

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

  • cost factor
  • salt
  • hash

Почему классические коллизии в bcrypt практически не применимы

Важно различать два уровня коллизий:

1. Коллизии хеш-функции

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

2. Практическая значимость в bcrypt

В bcrypt коллизии теряют прикладной смысл по нескольким причинам:

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

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


Роль соли в устранении классовых коллизий

Соль в bcrypt.js играет критическую роль в предотвращении массовых коллизий.

Если рассмотреть упрощённый вариант без соли:

  • hash(“password”) = X
  • hash(“password123”) = Y

При добавлении соли:

  • hash(“password”, salt1) = X1
  • hash(“password”, salt2) = X2

Даже одинаковые пароли всегда будут давать разные результаты из-за различной соли.

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


Адаптивная сложность и влияние на безопасность

bcrypt использует параметр cost factor, который определяет количество итераций вычислений.

2^n

где n — значение cost factor.

Каждое увеличение n увеличивает время вычисления экспоненциально, что делает перебор паролей существенно дороже по ресурсам.

Это напрямую влияет на устойчивость к атакам, но косвенно не связано с классическими коллизиями — скорее с практической невозможностью их эксплуатации.


Теоретические коллизии и криптографическая модель bcrypt

С точки зрения криптографии, bcrypt не позиционируется как функция, оптимизированная исключительно под минимизацию коллизий (как SHA-256). Его цель другая:

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

Поэтому даже если рассматривать пространство возможных входов, вероятность полезной коллизии стремится к пренебрежимо малому значению из-за комбинации:

  • соли
  • итераций
  • ограниченного сценария использования (пароли, а не произвольные данные)

Сравнение с классическими хеш-функциями

Свойство SHA-256 bcrypt
Быстродействие высокое намеренно низкое
Соль нет (по умолчанию) встроена
Коллизии критичны да практически нет
Назначение контроль целостности хранение паролей

Главное отличие заключается в том, что bcrypt не предназначен для быстрого поиска совпадений, а наоборот — для замедления любых попыток перебора.


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

При проверке пароля bcrypt.js не выполняет поиск совпадения хеша в базе данных. Вместо этого происходит следующее:

  1. Из сохранённого хеша извлекается соль и cost factor
  2. Введённый пароль хешируется с теми же параметрами
  3. Результаты сравниваются побайтно

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


Энтропия и пространство возможных значений

Пароли имеют ограниченную длину и алфавит, что создаёт конечное пространство входных данных. Однако bcrypt преобразует его в гораздо более широкое пространство выходных значений за счёт:

  • соли (увеличивает вариативность)
  • итераций (усложняет вычисление зависимости вход-выход)
  • внутренней структуры алгоритма EksBlowfish

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


Итоговая роль коллизий в контексте bcrypt.js

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

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

Основная задача bcrypt — не исключить коллизии как математическое явление, а сделать любые попытки их использования вычислительно бессмысленными.