В основе любой системы хранения паролей лежит преобразование исходной строки в фиксированное по длине значение — хеш. Для этого используются криптографические функции, которые должны обладать ключевыми свойствами: необратимостью и устойчивостью к коллизиям.
Коллизия в контексте хеширования — это ситуация, когда два разных входных значения дают одинаковый хеш-результат. Формально:
Для обычных хеш-функций общего назначения (например, SHA-1 или MD5) коллизии являются критической проблемой, поскольку они могут использоваться для подмены данных или обхода проверок целостности.
Однако в системах хранения паролей ситуация принципиально отличается: используются не просто хеш-функции, а ключевые деривационные функции (KDF), такие как bcrypt.
Библиотека bcrypt.js реализует алгоритм bcrypt, который специально разработан для безопасного хранения паролей. Его ключевые особенности:
Процесс выглядит следующим образом:
Итоговый хеш содержит:
Важно различать два уровня коллизий:
Это теоретическая возможность того, что два разных пароля дадут одинаковый результат.
В bcrypt коллизии теряют прикладной смысл по нескольким причинам:
Даже если гипотетически два разных пароля дали бы одинаковый итог, это не даёт атакующему полезного преимущества, потому что проверка пароля не основана на поиске обратного значения, а на сравнении через повторное хеширование с той же солью.
Соль в bcrypt.js играет критическую роль в предотвращении массовых коллизий.
Если рассмотреть упрощённый вариант без соли:
При добавлении соли:
Даже одинаковые пароли всегда будут давать разные результаты из-за различной соли.
Это полностью исключает возможность использования радужных таблиц и делает коллизии между пользователями практически бессмысленными.
bcrypt использует параметр cost factor, который определяет количество итераций вычислений.
2^n
где n — значение cost factor.
Каждое увеличение n увеличивает время вычисления экспоненциально, что делает перебор паролей существенно дороже по ресурсам.
Это напрямую влияет на устойчивость к атакам, но косвенно не связано с классическими коллизиями — скорее с практической невозможностью их эксплуатации.
С точки зрения криптографии, bcrypt не позиционируется как функция, оптимизированная исключительно под минимизацию коллизий (как SHA-256). Его цель другая:
Поэтому даже если рассматривать пространство возможных входов, вероятность полезной коллизии стремится к пренебрежимо малому значению из-за комбинации:
| Свойство | SHA-256 | bcrypt |
|---|---|---|
| Быстродействие | высокое | намеренно низкое |
| Соль | нет (по умолчанию) | встроена |
| Коллизии критичны | да | практически нет |
| Назначение | контроль целостности | хранение паролей |
Главное отличие заключается в том, что bcrypt не предназначен для быстрого поиска совпадений, а наоборот — для замедления любых попыток перебора.
При проверке пароля bcrypt.js не выполняет поиск совпадения хеша в базе данных. Вместо этого происходит следующее:
Таким образом, даже наличие теоретической коллизии не даёт возможности её использовать в реальной атаке без знания исходных параметров вычисления.
Пароли имеют ограниченную длину и алфавит, что создаёт конечное пространство входных данных. Однако bcrypt преобразует его в гораздо более широкое пространство выходных значений за счёт:
Это означает, что даже при большом количестве входов вероятность осмысленной коллизии остаётся теоретической, а не практической проблемой.
В отличие от классических криптографических хешей, где устойчивость к коллизиям является центральным свойством, в bcrypt:
Основная задача bcrypt — не исключить коллизии как математическое явление, а сделать любые попытки их использования вычислительно бессмысленными.