В bcrypt основным параметром, определяющим сложность хеширования, является cost factor (его также называют rounds или log rounds). Он задаёт количество вычислительных итераций, которые выполняет алгоритм при создании хеша пароля.
Математически bcrypt использует показатель степени двойки:
2^{cost factor}
Это означает, что фактическая вычислительная сложность растёт экспоненциально при увеличении значения cost factor.
Например:
Разница между значениями кажется небольшой на уровне числа, но в реальной системе она становится критической: увеличение cost всего на 1 удваивает время вычисления хеша.
В библиотеке bcrypt.js cost factor передаётся как второй аргумент функции генерации соли:
import bcrypt from 'bcryptjs';
const saltRounds = 10;
const password = 'user_password';
const hash = bcrypt.hashSync(password, saltRounds);
Здесь saltRounds определяет, насколько «дорогой» будет
операция хеширования.
Важно, что bcrypt.js сначала генерирует соль, в которой уже закодирован cost factor, а затем использует её для вычисления хеша:
const salt = bcrypt.genSaltSync(12);
const hash = bcrypt.hashSync(password, salt);
В этом случае cost factor фиксируется внутри соли и становится неотъемлемой частью результата.
bcrypt специально спроектирован так, чтобы быть медленным. Это не недостаток, а механизм защиты от атак перебора паролей.
При увеличении cost factor растёт:
Если условно принять:
То увеличение cost на единицу удваивает время вычисления.
Это поведение можно выразить через зависимость:
T(c) k ^{c}
где:
Низкий cost factor делает систему уязвимой к brute-force атакам.
Если хеш вычисляется слишком быстро, злоумышленник может перебрать миллионы паролей в секунду.
Типичные последствия:
Например, при cost = 8 или 9 современные GPU способны проверять огромные объёмы вариантов практически в реальном времени.
Слишком высокий cost factor приводит к обратной проблеме — деградации производительности системы.
В серверной среде это проявляется как:
Пример критичной ситуации:
bcrypt.hashSync(password, 14);
На слабом сервере или при высокой нагрузке это может занять сотни миллисекунд на одну операцию. При тысячах одновременных запросов система начинает деградировать.
bcrypt.js имеет синхронные и асинхронные версии функций.
Синхронная версия:
bcrypt.hashSync(password, 12);
Асинхронная версия:
bcrypt.hash(password, 12, (err, hash) => {
// результат
});
Разница критична:
При высоком cost factor синхронный вариант становится узким местом всей системы.
Выбор значения зависит от баланса:
Обычно используют диапазон:
Каждое увеличение на 1 удваивает стоимость вычислений, поэтому рост происходит не линейно, а экспоненциально.
Использование log2 для cost factor не случайно. Это позволяет:
Внутри bcrypt соль кодируется так, что cost factor является частью строки:
$2a$12$...
Здесь 12 — это и есть log2 cost factor.
Хотя формула задаёт теоретическую сложность, фактическое время зависит от:
На современных серверах разница может быть следующей:
В системах с высокой нагрузкой cost factor становится ключевым параметром архитектуры.
Если количество пользователей растёт, то суммарная нагрузка на bcrypt растёт линейно, но стоимость каждой операции — экспоненциально.
Это приводит к необходимости:
Типичные проблемы:
Безопасный cost factor не является постоянной величиной. Он должен пересматриваться по мере роста вычислительной мощности оборудования.
То, что было безопасно 10 лет назад, сегодня может быть недостаточно медленным, чтобы защитить от атак перебора.
Поэтому системы часто хранят cost factor внутри хеша и позволяют использовать разные значения одновременно, постепенно обновляя старые хеши при логине пользователя.
bcrypt позволяет естественным образом «старить» хеши:
Это создаёт динамическую модель безопасности без необходимости массовой миграции базы данных.
Cost factor является не просто числом, а ключевым параметром, определяющим:
Он превращает bcrypt из простой функции хеширования в регулируемый механизм компромисса между безопасностью и производительностью.