Proteção de APIs com Rate Limiting Manual em Node.js HTTP

Proteção de APIs com Rate Limiting Manual em Node.js HTTP

Servidores sem controle de tráfego estão vulneráveis a ataques de força bruta, negação de serviço (DoS) e consumo excessivo de recursos. A implementação de um middleware de Rate Limiting simples em Node.js resolve esse problema interceptando as requisições por IP e bloqueando conexões que excedam o limite estabelecido dentro de uma janela de tempo.

JavaScript

const http = require('http');

// Armazena a contagem de requisições por IP em memória
const taxaLimites = new Map();

/**
 * Middleware para controlar a taxa de requisições por IP
 * @param {http.IncomingMessage} req 
 * @param {http.ServerResponse} res 
 * @param {number} limiteMaximo - Máximo de requisições permitidas
 * @param {number} janelaMs - Intervalo de tempo em milissegundos
 * @returns {boolean} Retorna true se a requisição for permitida
 */
function rateLimiter(req, res, limiteMaximo = 5, janelaMs = 60000) {
  const ip = req.socket.remoteAddress || '127.0.0.1';
  const agora = Date.now();

  if (!taxaLimites.has(ip)) {
    taxaLimites.set(ip, { contagem: 1, inicioJanela: agora });
    return true;
  }

  const registro = taxaLimites.get(ip);

  // Reseta a contagem caso a janela de tempo tenha expirado
  if (agora - registro.inicioJanela > janelaMs) {
    registro.contagem = 1;
    registro.inicioJanela = agora;
    return true;
  }

  // Incrementa o contador de requisições
  registro.contagem += 1;

  // Bloqueia a requisição se exceder o limite
  if (registro.contagem > limiteMaximo) {
    res.writeHead(429, { 'Content-Type': 'application/json' });
    res.end(JSON.stringify({ erro: 'Muitas requisições. Tente novamente mais tarde.' }));
    return false;
  }

  return true;
}

// --- Exemplo Prático de Uso ---
const servidor = http.createServer((req, res) => {
  // Executa o rate limiter (limite de 3 requisições por minuto para teste)
  if (!rateLimiter(req, res, 3, 60000)) return;

  res.writeHead(200, { 'Content-Type': 'application/json' });
  res.end(JSON.stringify({ mensagem: 'Requisição processada com sucesso!' }));
});

servidor.listen(3000, () => {
  console.log('Servidor rodando em http://localhost:3000');
});

Pontos-chave

  • Status HTTP 429 Too Many Requests: É o código de status padrão da RFC 6585 para sinalizar ao cliente que o limite de requisições foi atingido.
  • Captura do Endereço IP: Utiliza req.socket.remoteAddress; em ambientes com proxies reversos (ex: Nginx, Cloudflare), deve-se ler o cabeçalho x-forwarded-for.
  • Gerenciamento de Memória em Produção: O uso de Map em memória é ideal para testes e serviços simples, mas para aplicações distribuídas ou com tráfego alto recomenda-se utilizar um banco em memória como Redis.
  • Limpeza Automática de Chaves: Para evitar memory leaks com conexões de muitos IPs diferentes, implemente uma rotina de expiração via setInterval para apagar registros antigos do Map.

Thales de Oliveira Gomes

Thales de Oliveira Gomes é gestor de Tecnologia da Informação, especialista em infraestrutura de redes, computação em nuvem e operações de TI hospitalar, com mais de 18 anos de experiência na área. Graduado em Gestão de TI e pós-graduado em Engenharia de Redes e Telecomunicações, Cloud Computing, Redes de Computadores e Gestão Hospitalar, construiu uma trajetória sólida liderando projetos de alta complexidade, como a implementação e migração para nuvem de sistemas ERP de grande porte. Sua atuação no setor o levou a ser indicado ao prêmio IT Leaders Brasil na categoria Rising Leaders. Além da carreira corporativa e da paixão por tecnologia, Thales é autor independente com mais de 70 obras publicadas sobre redes, segurança da informação, Linux e física, além de criador de conteúdo no blog Vetor Tech e na plataforma CiberDicas. No universo das artes e do entretenimento, atua como produtor de música eletrônica sob o projeto Yknex, cria ilustrações digitais e compartilha walkthroughs de games no YouTube.

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *