Brute-force атаки на форму аутентификации основаны на переборе паролей до получения успешного входа. В отличие от классических переборов, современные атаки используют распределённые ботнеты, словари утекших паролей и высокоскоростные HTTP-клиенты. Основная цель — обойти механизм проверки пароля, а не угадать его вручную.
На уровне приложения защита от таких атак строится не на одном механизме, а на комбинации криптографических и поведенческих ограничений. Библиотека bcrypt.js решает только часть задачи — замедление проверки пароля за счёт вычислительно дорогого хэширования.
bcrypt — это адаптивная функция хэширования паролей, основанная на Blowfish. Она специально спроектирована так, чтобы:
Однако важно понимать ограничение: bcrypt защищает хранимые пароли, но не защищает endpoint логина от перебора запросов.
Если атакующий может отправлять 10 000 запросов в секунду к
/login, bcrypt лишь делает каждый запрос дорогим, но не
блокирует саму возможность атаки.
Ключевой параметр bcrypt — cost factor (обычно обозначается как
saltRounds в Node.js реализации).
Он задаёт количество итераций:
Пример использования:
import bcrypt fr om 'bcryptjs';
const password = 'user_password';
const saltRounds = 12;
const hash = await bcrypt.hash(password, saltRounds);
Практическое влияние:
Важно учитывать, что увеличение cost factor повышает устойчивость к перебору, но одновременно усиливает эффект DoS при атаке на логин-эндпоинт.
Типичный процесс проверки:
const isMatch = await bcrypt.compare(password, user.passwordHash);
Именно этот вызов становится «дорогой операцией», которую атакующий может эксплуатировать.
Если система не ограничивает частоту вызовов, злоумышленник получает возможность:
Первый обязательный механизм — ограничение частоты запросов.
Часто используется middleware на уровне Express:
import rateLimit fr om 'express-rate-lim it';
const loginLimiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 20,
standardHeaders: true,
legacyHeaders: false,
});
app.post('/login', loginLimiter, loginHandler);
Принцип:
IP-лимиты недостаточны из-за:
Поэтому добавляется вторичный слой:
Пример логики:
const key = `${ip}:${email}`;
Альтернатива жёсткой блокировке — увеличение задержки ответа.
const delay = Math.min(1000 * 2 ** failedAttempts, 30000);
await new Promise(r => setTimeout(r, delay));
Эффект:
Механизм блокировки аккаунта после N неудачных попыток:
Пример логики:
if (user.failedAttempts >= 5) {
user.lockUntil = Date.now() + 15 * 60 * 1000;
}
Однако этот подход имеет риски:
Даже при неправильном пароле система должна вести себя одинаково по времени.
Опасность возникает, если:
Это позволяет угадывать существование аккаунта.
Решение:
const fakeHash = '$2a$12$invalidsaltinvalidsaltinv';
await bcrypt.compare(password, user?.passwordHash || fakeHash);
Brute-force часто комбинируется с перебором email/логинов.
Защита включает:
одинаковые ответы API:
одинаковое время ответа;
отсутствие различий в HTTP статусах между ошибками.
CAPTCHA используется как дополнительный слой после:
Она не заменяет bcrypt или rate limiting, а дополняет их, снижая автоматизацию атак.
В микросервисной архитектуре защита должна быть централизованной:
Пример Redis-based throttling:
await redis.incr(`login:${ip}`);
await redis.expire(`login:${ip}`, 900);
Это критично, поскольку локальный rate limiting не работает в кластере Node.js.
Без наблюдаемости защита неэффективна.
Фиксируются:
Метрики позволяют:
Комбинированная схема обычно включает:
Такой набор создаёт многоуровневую систему, где bcrypt отвечает только за криптографическую стойкость хранения, а остальные механизмы блокируют саму возможность эффективного перебора.