В алгоритме bcrypt ключевым параметром является cost factor (также называемый log rounds или work factor). Он определяет количество итераций, через которые проходит алгоритм при вычислении хеша.
2^{cost} =
Рост значения cost увеличивает вычислительную сложность формирования хеша экспоненциально. Это означает, что увеличение даже на единицу существенно замедляет процесс хеширования.
bcrypt автоматически включает cost factor внутрь итогового хеша. Строка хеша обычно выглядит следующим образом:
$2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy
Где:
$2a$ — версия алгоритма10 — cost factorТаким образом, bcrypt является самодостаточным: для проверки пароля не требуется отдельно хранить параметры генерации.
В некоторых архитектурных решениях возникает идея хранить cost factor отдельно от строки хеша, например:
password_costИ при верификации использовать его вручную:
bcrypt.compare(password, hashFromDb, costFromDb)
или при генерации:
bcrypt.hash(password, costFromConfig)
На первый взгляд это может показаться удобным для централизованного управления производительностью.
Разные окружения могут иметь разные требования:
Вынесение параметра позволяет быстро переключать режимы без пересоздания хешей.
Иногда рассматривается идея адаптации cost factor:
При обновлении параметров безопасности иногда предполагается хранение “версии хеша” отдельно:
Ключевой архитектурный факт:
bcrypt-хеш уже содержит cost factor внутри себя и не требует внешних данных для проверки.
Это означает:
Если cost хранится отдельно, возникает рассинхронизация:
В результате:
При внешнем хранении параметра появляется возможность подмены:
При обновлении cost factor стандартный подход bcrypt:
При внешнем хранении требуется дополнительная проверка:
Это увеличивает сложность и вероятность ошибок.
bcrypt задуман как формат:
При внешнем cost:
При анализе базы данных стандартный bcrypt-хеш содержит всю необходимую информацию:
При внешнем хранении:
Дополнительное поле cost_factor:
Библиотека bcrypt.js строго следует стандарту bcrypt и:
compare$2a$,
$2b$, $2y$Пример:
const bcrypt = require('bcryptjs');
const hash = bcrypt.hashSync('password', 12);
bcrypt.compareSync('password', hash); // cost извлекается автоматически
Вместо внешнего хранения используется стратегия rehash on login:
const currentCost = 12;
const legacyThreshold = 10;
function verifyAndUpgrade(password, hash) {
const isValid = bcrypt.compareSync(password, hash);
if (!isValid) return false;
const extractedCost = parseInt(hash.split('$')[2], 10);
if (extractedCost < currentCost) {
const newHash = bcrypt.hashSync(password, currentCost);
return { valid: true, upgrade: newHash };
}
return { valid: true };
}
Ключевая идея:
Если cost factor становится отдельной сущностью, система фактически перестаёт использовать bcrypt как самодостаточный формат хранения паролей и превращается в гибридную модель:
Это приводит к:
Встроенный cost factor внутри bcrypt-хеша обеспечивает:
Любое внешнее вынесение этого параметра разрушает одно из базовых свойств алгоритма — самодостаточность хеша.