Утечка базы данных, содержащей только bcrypt-хеши паролей, не эквивалентна мгновенной компрометации всех учётных записей, однако представляет долгосрочную криптографическую угрозу. Основная причина — свойства самого bcrypt, который относится к адаптивным функциям хеширования паролей с вычислительно дорогим сравнением.
Ключевые свойства bcrypt:
Несмотря на это, компрометация базы означает, что атакующий получает оффлайн-доступ к проверке паролей без ограничений по количеству попыток и без механизмов блокировки аккаунта.
При утечке базы с bcrypt-хешами:
Даже при bcrypt с высоким cost, слабые пароли (короткие, словарные, повторяющиеся) становятся уязвимыми в разумные сроки.
Библиотека bcrypt.js реализует bcrypt на JavaScript и используется как в Node.js, так и в браузерных окружениях. Основные операции:
bcrypt.hashbcrypt.compareПример проверки пароля:
import bcrypt from "bcryptjs";
const password = "user_password";
const hash = await bcrypt.hash(password, 12);
const isValid = await bcrypt.compare(password, hash);
Внутри хеша уже содержится salt и cost factor, например:
$2a$12$......................
Компрометация базы с bcrypt-хешами требует исходить из предположения, что часть паролей будет восстановлена атакующим.
Первый критический шаг — принудительный выход всех пользователей:
Это ограничивает использование уже полученных сессий даже при последующем восстановлении пароля.
Если утечка подтверждена:
Важно учитывать: bcrypt не позволяет «защитить» уже утекший хеш, так как он предназначен только для проверки, а не для восстановления.
Если утечка произошла при недостаточном cost factor (например, 8–10), необходимо увеличить параметр сложности.
const NEW_COST = 14;
const newHash = await bcrypt.hash(password, NEW_COST);
Увеличение cost:
Однако увеличение cost не защищает уже утекшие хеши — только будущие.
Практическая защита включает проверку актуальности параметров хеша при логине.
bcrypt.js позволяет определить необходимость повторного хеширования:
function needsRehash(hash, currentCost = 14) {
const parts = hash.split("$");
const cost = parseInt(parts[2], 10);
return cost < currentCost;
}
Использование:
const isValid = await bcrypt.compare(password, hash);
if (isValid && needsRehash(hash)) {
const newHash = await bcrypt.hash(password, 14);
// сохранить новый хеш в базе
}
Таким образом происходит постепенная миграция пользователей на более стойкие параметры без принудительного сброса.
bcrypt не использует секретный ключ сервера. Для повышения стойкости после утечки применяется pepper — дополнительная секретная строка, не хранящаяся в базе данных.
const pepper = process.env.PEPPER_SECRET;
const hash = await bcrypt.hash(password + pepper, 12);
При утечке базы атакующий не сможет провести полноценный оффлайн brute-force без знания pepper.
После инцидента необходимо учитывать, что часть атак может происходить уже оффлайн, но последствия проявляются в онлайн-среде:
Для борьбы с этим применяются:
Основная опасность утечки bcrypt-хешей заключается не в расшифровке всех паролей, а в статистическом восстановлении части из них.
После этого атакующий:
Даже 1–5% восстановленных паролей достаточно для цепной компрометации внешних систем пользователей.
bcrypt остаётся устойчивым при корректных параметрах:
Однако криптостойкость bcrypt не компенсирует организационные риски: