Rate Limiting в Node.js: Защита API от перегрузок и злоумышленников
Rate limiting (ограничение скорости запросов) — это критически важный механизм для любого веб-приложения на Node.js. Он позволяет контролировать количество запросов, которые клиент может отправить на сервер за определенный промежуток времени. Без rate limiting ваше API уязвимо для DDoS-атак, случайных перегрузок и чрезмерного потребления ресурсов.
Зачем нужен Rate Limiting?
- Защита от брутфорса: Предотвращает многократные попытки входа в систему.
- Предотвращение DDoS: Ограничивает влияние атак на отказ в обслуживании.
- Справедливое распределение ресурсов: Гарантирует равный доступ для всех пользователей.
- Экономия затрат: Снижает нагрузку на серверы и базы данных.
- Соответствие SLA: Выполнение соглашений об уровне обслуживания.
Основные алгоритмы Rate Limiting
Существует несколько подходов к реализации ограничения скорости. Рассмотрим наиболее популярные:
1. Sliding Window (Скользящее окно)
Самый распространенный алгоритм. Запросы группируются во временные окна (например, 1 минута). Если количество запросов превышает лимит, следующие запросы отклоняются до начала нового окна.
2. Token Bucket (Ведро токенов)
Виртуальное "ведро" содержит токены. Каждый запрос потребляет один токен. Токены пополняются с фиксированной скоростью. Если ведро пусто, запрос отклоняется.
3. Leaky Bucket (Дырявое ведро)
Запросы поступают в очередь и обрабатываются с постоянной скоростью. Если очередь переполняется, запросы отбрасываются.
Библиотеки для Rate Limiting в Node.js
1. express-rate-limit
Самая популярная библиотека для Express.js. Простая в использовании и настраиваемая.
const rateLimit = require('express-rate-limit');
// Создаем middleware для ограничения запросов
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 минут
max: 100, // максимум 100 запросов за окно
message: 'Слишком много запросов, попробуйте позже.',
standardHeaders: true, // Возвращает RateLimit-* заголовки
legacyHeaders: false, // Отключает X-RateLimit-* заголовки
});
// Применяем ко всем маршрутам
app.use(limiter);
// Или только к конкретному маршруту
app.use('/api/login', limiter);
2. bottleneck
Универсальная библиотека, работающая с любыми асинхронными операциями. Поддерживает алгоритмы Token Bucket и Leaky Bucket.
const Bottleneck = require('bottleneck');
// Создаем лимитер: 5 запросов в секунду
const limiter = new Bottleneck({
minTime: 200, // 200 мс между запросами
maxConcurrent: 5, // максимум 5 одновременных запросов
reservoir: 100, // начальное количество токенов
reservoirRefreshAmount: 100,
reservoirRefreshInterval: 60 * 1000, // пополнение раз в минуту
});
// Оборачиваем функцию в лимитер
async function fetchData(url) {
const response = await fetch(url);
return response.json();
}
const limitedFetch = limiter.wrap(fetchData);
// Использование
const data = await limitedFetch('https://api.example.com/data');
3. rate-limiter-flexible
Гибкая библиотека с поддержкой Redis, MongoDB, Memcached и других хранилищ. Идеальна для распределенных систем.
const { RateLimiterRedis } = require('rate-limiter-flexible');
const Redis = require('ioredis');
const redisClient = new Redis();
const rateLimiter = new RateLimiterRedis({
storeClient: redisClient,
keyPrefix: 'middleware',
points: 10, // 10 запросов
duration: 1, // за 1 секунду
});
app.use(async (req, res, next) => {
try {
await rateLimiter.consume(req.ip);
next();
} catch (rejRes) {
res.status(429).send('Слишком много запросов');
}
});
Практические примеры
Пример 1: Rate Limiting для API ключей
Ограничиваем запросы для каждого API ключа отдельно:
const rateLimit = require('express-rate-limit');
const apiKeyLimiter = rateLimit({
windowMs: 60 * 60 * 1000, // 1 час
max: 1000,
keyGenerator: (req) => req.headers['x-api-key'] || req.ip,
handler: (req, res) => {
res.status(429).json({
error: 'Превышен лими Также в библиотеке
Rate limiting в Rust: библиотеки governor, leaky-bucket и middleware для веб-серверов
PDFKit для JavaScript (Node.js): полное руководство с примерами
Интернационализация (i18n) в C++: полное руководство с gettext и ICU
PDF генерация в Swift (iOS/macOS): UIGraphicsPDFRenderer, PDFKit и Core Graphics