Objetivos de aprendizado
Depois de ler este artigo, você vai conseguir:
- Entender o que um provedor filtra e o que continua sendo problema da sua aplicação
- Configurar limite de requisições, timeouts e limite de corpo em uma API Node.js
- Testar com curl se a proteção está funcionando
Um ataque DDoS (negação de serviço distribuída) usa muitas máquinas ao mesmo tempo para deixar um alvo sem resposta. Segundo a CISA, os atacantes costumam usar botnets, redes de dispositivos sequestrados. O efeito para você é simples: usuários legítimos não conseguem acessar o site, a API ou o bot.
Não existe proteção total só com código. Parte do ataque precisa ser filtrada antes de chegar ao seu servidor, e outra parte você resolve na própria aplicação. Os exemplos abaixo mostram o que cada camada faz e como configurar a sua, usando uma API em Node.js.
Que tipos de ataque DDoS existem?#
Três famílias cobrem quase tudo:
- Volumétrico: inunda o link de rede com tráfego (camadas 3 e 4 do modelo OSI). Seu código nem chega a ser executado, porque a banda acaba antes.
- De protocolo: abusa do funcionamento do TCP, como milhares de conexões semiabertas, para esgotar tabelas de estado do servidor ou do firewall.
- De aplicação (camada 7): envia requisições HTTP aparentemente legítimas, como milhares de buscas por segundo numa rota pesada. É o mais barato de lançar e o que mais depende de você.
Essa divisão decide a defesa. Os dois primeiros só quem tem muita capacidade de rede consegue absorver. O terceiro você reduz com cache, limites e código eficiente.
O que seu provedor faz e o que sobra para você?#
A Cloudflare, por exemplo, descreve mitigação automática nas camadas 3, 4 e 7 aplicada na borda da rede. Esse é o modelo comum: uma CDN ou um proxy reverso recebe todo o tráfego, descarta o que reconhece como ataque e repassa o resto.
Mesmo com isso, o que passa pelo filtro ainda chega ao seu código. Sobram para você:
- limitar quantas requisições cada cliente faz;
- fechar conexões lentas ou paradas;
- recusar corpos de requisição enormes;
- cachear respostas caras;
- não deixar a aplicação acessível por um caminho que ignore a borda.
Como limitar requisições por cliente?#
O rate limit responde 429 (Too Many Requests) quando um cliente passa do limite em uma janela de tempo, como descreve a MDN. Em Express, o pacote express-rate-limit faz isso. Os exemplos usam uma versão recente do Node.js e Express 5.
npm install express express-rate-limit// server.js
import express from "express";
import { rateLimit } from "express-rate-limit";
const app = express();
// Atrás de 1 proxy (CDN ou balanceador), use o IP real do cliente.
// Ajuste o número à sua realidade: veja a seção sobre trust proxy.
app.set("trust proxy", 1);
// Limite global: 100 requisições por minuto por IP.
app.use(
rateLimit({
windowMs: 60 * 1000,
limit: 100,
standardHeaders: "draft-7",
legacyHeaders: false,
}),
);
// Rotas sensíveis têm limite mais baixo.
const loginLimiter = rateLimit({
windowMs: 15 * 60 * 1000,
limit: 10,
standardHeaders: "draft-7",
legacyHeaders: false,
});
// Corpo JSON limitado a 100 KB.
app.use(express.json({ limit: "100kb" }));
app.get("/", (req, res) => res.json({ ok: true }));
app.post("/login", loginLimiter, (req, res) => res.json({ ok: true }));
const server = app.listen(process.env.PORT ?? 3000);
// Corta conexões lentas (slowloris) e requisições que nunca terminam.
server.headersTimeout = 15_000;
server.requestTimeout = 30_000;Pontos que valem atenção:
- Na documentação do pacote,
limité o máximo por janela ewindowMso tamanho da janela em milissegundos. O padrão da biblioteca élimit: 5por minuto, então sempre defina o seu. legacyHeaders: falsedesliga os cabeçalhosX-RateLimit-*antigos, estandardHeadersliga os cabeçalhos padronizados do IETF.- O contador fica na memória do processo por padrão. Com várias instâncias, cada uma conta separado. Para um limite compartilhado, use um store externo, como o Redis.
Por que o trust proxy importa tanto?#
Atrás de um proxy, req.ip seria o endereço do proxy, e o rate limit trataria todos os usuários como um só: um cliente abusivo bloquearia todo mundo. O trust proxy diz ao Express em quais valores do cabeçalho X-Forwarded-For confiar, conforme o guia do Express.
O erro oposto também é perigoso. Se você confia em mais saltos do que existem de verdade, o cliente forja o cabeçalho e escolhe o IP que quiser, o que derruba o rate limit. Por isso:
- Descubra quantos proxies existem entre o usuário e a sua aplicação.
- Use esse número em
trust proxy, e nãotrue, a menos que o último proxy sobrescreva o cabeçalho. - Confirme registrando
req.ipem uma rota de teste, a partir de dois IPs diferentes.
Quais timeouts configurar?#
Um ataque de conexão lenta mantém sockets abertos enviando poucos bytes por vez. A documentação do Node.js diz que server.headersTimeout e server.requestTimeout devem ter valor diferente de zero para proteger contra negação de serviço quando o servidor não está atrás de um proxy reverso. O padrão do requestTimeout é 300 segundos e o do headersTimeout é o menor valor entre requestTimeout e 60 segundos. No código acima eles caem para 15 e 30 segundos. O Node verifica esses prazos a cada 30 segundos por padrão (connectionsCheckingInterval), então o corte pode vir um pouco depois do valor configurado.
Se sua API recebe uploads grandes, 30 segundos para o corpo inteiro pode ser pouco. Nesse caso, mantenha um requestTimeout mais alto e aceite uploads por um serviço separado.
Como reduzir o custo de cada requisição?#
No ataque de camada 7, o dano é proporcional ao quanto cada requisição custa. Três ajustes baratos:
- Cache: sirva páginas e respostas públicas com
Cache-Controlpara que a borda responda sem chamar o seu código. Veja o que é Cache-Control. - Rotas pesadas atrás de autenticação: buscas, exportações e geração de relatórios não precisam estar abertas ao mundo.
- Paginação e limites: nunca devolva uma tabela inteira nem aceite
limit=1000000.
O restante do endurecimento da API, como validação de entrada e logs, está no checklist de produção de uma API.
Como testar se funciona?#
Com o servidor rodando, dispare 130 requisições seguidas e conte os códigos de resposta:
for i in $(seq 1 130); do
curl -s -o /dev/null -w "%{http_code}\n" http://localhost:3000/
done | sort | uniq -cA saída esperada com limit: 100, se você rodar logo após iniciar o servidor, é esta:
100 200
30 429Para o timeout de cabeçalhos, envie uma requisição incompleta (sem a linha em branco final) e espere:
(printf 'GET / HTTP/1.1\r\nHost: localhost\r\n'; sleep 60) | nc localhost 3000
# o servidor responde 408 Request Timeout e fecha a conexãoEm produção, o teste real é observar os logs: muitos 429 vindos de poucos IPs mostram o limite agindo, e picos de tráfego em rotas inesperadas indicam o alvo do ataque.
Quais erros são comuns?#
- Rate limit sem
trust proxy: todos os usuários compartilham o IP do proxy e são bloqueados juntos. trust proxy: truesem necessidade: o cliente forja o IP e escapa do limite.- Aplicação acessível pelo IP direto: o atacante ignora a CDN e bate direto no servidor. Responda só pelo domínio ou aceite tráfego apenas da borda.
- Limite igual para tudo: login e busca precisam de limites bem menores que arquivos estáticos.
- Contagem em memória com várias instâncias: o limite real vira N vezes o configurado.
Como fazer isso na Square Cloud#
Na Square Cloud, a primeira camada vem em todos os planos: mitigação de DDoS nas camadas 3, 4 e 7 e um WAF na frente das aplicações, numa rede com CDN Anycast de mais de 200 pontos de presença (baseada na Cloudflare) e até 10 Gbps por servidor. Só a porta 80 da aplicação recebe tráfego, publicado por HTTPS no subdomínio squareweb.app ou no seu domínio. Nenhuma mitigação torna um serviço imune, e a segunda camada continua sendo sua, porque o código é seu.
Os exemplos deste artigo se encaixam assim. A CDN respeita o Cache-Control da sua aplicação, então as respostas públicas que você marcar como cacheáveis saem da borda sem chamar o seu código, e o purge de cache apaga o cache do host quando você publica uma mudança. Confirme o valor de trust proxy com o teste de req.ip a partir de dois IPs, como na seção sobre ele. Se você distribuir um domínio entre várias aplicações com load balancing (a partir do Standard), leve o contador do rate limit para a hospedagem de Redis, no mesmo datacenter, para o limite não virar N vezes o configurado.
Para acompanhar um ataque, o analytics web incluído em todo plano mostra rotas, países, status codes e bots verificados: um pico de 429 numa rota mostra o limite agindo. Veja o que a rede inclui na página de rede e conheça a hospedagem de Redis.
Infraestrutura
Mitigação de DDoS L3/L4/L7 e WAF em todos os planos
Perguntas frequentes
Dá para se proteger de DDoS sozinho, sem provedor?
Só de ataques pequenos. Um ataque volumétrico satura o link de rede antes de chegar ao seu código, então a mitigação precisa acontecer na borda, em quem tem capacidade de rede para absorver o tráfego.
Rate limit por IP resolve DDoS?
Resolve abuso de um IP ou de poucos, mas não um ataque distribuído com milhares de IPs. Ele é uma camada da defesa, junto com cache, WAF e mitigação no provedor.
Meu bot do Discord precisa de proteção contra DDoS?
Em geral o risco é baixo, porque o bot abre conexões de saída para o Gateway e não recebe tráfego público. O ponto de atenção é qualquer porta ou webhook exposto e o IP da sua máquina, se o bot roda em casa.
Como saber se estou sob ataque DDoS?
Sinais comuns são lentidão súbita, picos de requisições vindas de muitos IPs para as mesmas rotas e consumo alto de CPU ou muitas conexões abertas sem aumento de usuários reais. Confirme olhando os logs de acesso.
Mais em Segurança
Ver todos os 10 artigos- O que é ataque de força bruta e como se protegerAtaque de força bruta é testar senhas em massa até acertar uma. Veja os tipos (spraying, credential stuffing), como funcionam e as defesas com código que roda.
- Minha aplicação foi invadida: o que fazer agoraSe a sua aplicação foi invadida, contenha o acesso, troque todos os segredos e preserve os logs antes de limpar. Veja a ordem certa, a causa e como voltar.
- Checklist de segurança para quem publica bot, site ou APIChecklist de segurança antes de publicar bot, site ou API: segredos em variáveis de ambiente, dependências, HTTPS, cabeçalhos, permissões mínimas e logs.
- Vazou o token do bot? O que fazer agoraSe o token do bot vazou, redefina-o no Portal do Discord (ou com /token no BotFather) antes de qualquer outra coisa. Veja a ordem certa e como checar o estrago.