Rate Limiting em JavaScript (Node.js): Protegendo APIs com express-rate-limit
No desenvolvimento web moderno, proteger aplicações servidoras contra carga excessiva e ataques maliciosos é uma tarefa crítica. Um dos mecanismos de proteção mais eficazes é o rate limiting (limitação de frequência de requisições). Esta abordagem permite controlar o número de requisições que um cliente (endereço IP, usuário ou sessão) pode enviar ao servidor em um determinado período de tempo. No ecossistema Node.js e Express, a biblioteca mais popular e confiável para implementar rate limiting é o express-rate-limit.
O que é rate limiting e por que é necessário?
Rate limiting é uma técnica usada para gerenciar o tráfego em uma rede. Ela previne o abuso dos recursos do servidor, protegendo contra:
- Ataques DoS/DDoS — requisições em massa com o objetivo de derrubar o servidor.
- Ataques de força bruta — tentativas de adivinhar senhas ou tokens de acesso.
- Web scraping — coleta automatizada de dados de um site.
- Uso excessivo da API — quando um único cliente consome mais recursos do que o permitido.
Sem rate limiting, sua aplicação pode se tornar vulnerável e instável, especialmente com o crescimento da base de usuários.
A biblioteca express-rate-limit
express-rate-limit é um middleware para Express.js que oferece uma maneira simples e flexível de limitar requisições. Ele se integra à cadeia de processamento de requisições e rastreia automaticamente o número de acessos de cada cliente. A biblioteca suporta diversos armazenamentos (em memória, Redis, MongoDB e outros), tornando-a escalável para sistemas distribuídos.
Instalação
Para começar, instale a biblioteca via npm:
npm install express-rate-limitUso básico
O exemplo mais simples é limitar todas as rotas da aplicação a 100 requisições por hora a partir de um único endereço IP:
const rateLimit = require('express-rate-limit');const express = require('express');const app = express();
// Cria o limitadorconst limiter = rateLimit({ windowMs: 60 * 60 * 1000, // 1 hora max: 100, // máximo de 100 requisições message: 'Muitas requisições do seu IP. Por favor, tente novamente mais tarde.', standardHeaders: true, // Retorna cabeçalhos padrão RateLimit-* legacyHeaders: false, // Desativa cabeçalhos X-RateLimit-*});
// Aplica a todas as rotasapp.use(limiter);
app.get('/', (req, res) => { res.send('Página inicial');});
app.listen(3000, () => { console.log('Servidor rodando na porta 3000');});Configuração para diferentes rotas
Frequentemente, é necessário ter limites diferentes para endpoints distintos. Por exemplo, para a rota de login, pode-se definir um limite mais restritivo:
const rateLimit = require('express-rate-limit');
// Limite restritivo para /api/loginconst loginLimiter = rateLimit({ windowMs: 15 * 60 * 1000, // 15 minutos max: 5, // 5 tentativas de login message: { error: 'Muitas tentativas de login. Tente novamente em 15 minutos.', retryAfter: 15 }, keyGenerator: (req) => { // Usa IP + nome de usuário para bloqueio mais preciso return req.ip + req.body.username; }});
app.post('/api/login', loginLimiter, (req, res) => { // Lógica de autenticação res.send('Login realizado');});
// Limite mais brando para API públicaconst apiLimiter = rateLimit({ windowMs: 60 * 1000, // 1 minuto max: 30, // 30 requisições por minuto message: 'Limite de requisições à API excedido.'});
app.use('/api/', apiLimiter);Funcionalidades avançadas
Armazenamentos personalizados
Por padrão, os dados são armazenados na memória do processo. Para produção, recomenda-se