bcrypt — это алгоритм хеширования паролей, построенный вокруг вычислительно тяжёлой функции Blowfish. В JavaScript-реализации bcrypt.js эта тяжесть становится особенно заметной, поскольку вся криптографическая работа выполняется в пользовательском пространстве и полностью ложится на CPU процесса Node.js.
Ключевая особенность bcrypt заключается в его намеренно высокой вычислительной стоимости. Алгоритм включает многократное расширение ключа (key expansion) и повторяющиеся раунды шифрования, причём количество итераций регулируется параметром cost factor (work factor). Рост этого параметра экспоненциально увеличивает время вычисления хеша.
T = 2^{cost} t_0
где (T) — время вычисления, а (t_0) — базовая стоимость одного цикла.
Именно эта экспоненциальная зависимость и делает bcrypt CPU-bound задачей: время работы определяется не вводом/выводом, а чистой вычислительной нагрузкой на процессор.
В случае bcrypt.js ситуация усиливается тем, что реализация написана на чистом JavaScript без нативных криптографических расширений. Это означает:
Node.js построен вокруг однопоточного event loop. Любая CPU-bound операция блокирует этот цикл до завершения вычислений. bcrypt-хеширование — типичный пример такой операции.
При вызове:
bcrypt.hash(password, 12, (err, hash) => {
// callback
});
даже асинхронный интерфейс не избавляет от вычислительной нагрузки. Асинхронность здесь означает лишь неблокирующий API с точки зрения JavaScript-кода, но сама операция выполняется в пуле потоков libuv или в event loop-подобной модели исполнения, конкурируя за CPU.
При высокой нагрузке это приводит к:
Особенно критично это в API-сервисах с частыми операциями логина или регистрации.
Существует нативный пакет bcrypt (C++ binding), который использует оптимизированные реализации OpenBSD bcrypt. В отличие от него bcrypt.js:
Это приводит к тому, что при одинаковом cost factor:
Каждый запрос на хеширование пароля конкурирует за CPU. При высокой частоте регистраций или логинов сервер начинает «проседать» по задержкам даже в unrelated endpoints.
Типичная картина:
bcrypt часто становится точкой атаки. Массовые запросы на:
создают искусственную нагрузку на CPU. Поскольку операция дорогая, даже небольшой поток запросов способен:
В многопользовательских системах bcrypt создаёт дисбаланс:
Это приводит к эффекту «голодания» менее ресурсоёмких операций.
Вертикальное масштабирование (увеличение CPU) помогает лишь частично, поскольку:
Горизонтальное масштабирование требует балансировки, но не решает проблему CPU-bound характера самой операции.
Cost factor — главный рычаг безопасности и одновременно главный источник нагрузки.
T ^{c}
где (c) — cost factor.
Практическая интерпретация:
Разница между соседними значениями не линейная, а экспоненциальная, поэтому увеличение на +1 может удвоить или утроить время вычисления.
В production-среде с bcrypt.js наблюдаются типичные эффекты:
Особенно выражено это в системах без выделенного worker pool для криптографических операций.
Использование bcrypt в Node.js требует компенсации CPU-bound природы:
В кластерах Node.js (cluster module) проблема не исчезает полностью, но распределяется между процессами, уменьшая давление на один event loop.
bcrypt не является единственным алгоритмом хеширования, но он один из самых дорогих по CPU:
bcrypt.js при этом остаётся наиболее «чисто CPU-bound» в рамках JavaScript, так как полностью лишён нативной оптимизации.
Использование bcrypt.js в серверных приложениях напрямую влияет на:
При высоконагруженных системах именно CPU-bound природа bcrypt становится ограничивающим фактором архитектуры, а не второстепенной деталью реализации.