Middleware de Segurança
Fortaleça APIs Express com helmet para cabeçalhos de segurança, cors para política de origem cruzada e limitação de taxa para prevenção de abusos.
Receita
Cartão de receita de referência rápida - pronto para copiar e colar.
import express from "express";
import helmet from "helmet";
import cors from "cors";
import rateLimit from "express-rate-limit";
const app = express();
app.set("trust proxy", 1);
app.use(helmet());
app.use(cors({
origin: process.env.ALLOWED_ORIGIN ?? "https://app.example.com",
credentials: true,
}));
app.use(express.json({ limit: "1mb" }));
app.use(rateLimit({
windowMs: 15 * 60 * 1000,
max: 100,
standardHeaders: true,
}));Quando usar isso: Toda API voltada para o público. Middleware de segurança não é opcional para endpoints de produção.
Exemplo de Trabalho
import express from "express";
import helmet from "helmet";
import cors from "cors";
import rateLimit from "express-rate-limit";
const app = express();
app.set("trust proxy", 1);
app.use(helmet({
contentSecurityPolicy: false, // habilite se estiver servindo HTML do Express
crossOriginResourcePolicy: { policy: "cross-origin" },
}));
const allowedOrigins = ["https://app.example.com", "https://staging.example.com"];
app.use(cors({
origin(origin, callback) {
if (!origin || allowedOrigins.includes(origin)) {
callback(null, true);
} else {
callback(new Error("Não permitido por CORS"));
}
},
credentials: true,
}));
const apiLimiter = rateLimit({
windowMs: 60_000,
max: 60,
standardHeaders: true,
legacyHeaders: false,
});
const authLimiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 10,
message: { error: "Muitas tentativas de login" },
});
app.use(express.json({ limit: "1mb" }));
app.use("/api", apiLimiter);
app.post("/api/auth/login", authLimiter, loginHandler);
app.get("/health", (_req, res) => res.json({ ok: true }));
function loginHandler(_req: express.Request, res: express.Response) {
res.json({ token: "..." });
}O que isso demonstra:
helmetdefine cabeçalhos de segurança (X-Content-Type-Options, HSTS, etc.)- Lista de permissões de origem CORS dinâmica
- Limite geral de taxa de API mais limite mais rigoroso para endpoint de autenticação
- Verificação de saúde isenta de middleware pesado (montada antes do escopo do limitador)
Mergulho Profundo
Como Funciona
- helmet: Define cabeçalhos de resposta HTTP que mitigam XSS, clickjacking e MIME sniffing
- cors: Adiciona cabeçalhos
Access-Control-*; navegadores aplicam CORS, chamadas de servidor para servidor o ignoram - rate-limit: Rastreia requisições por IP (ou chave personalizada) em memória ou em um armazenamento Redis
Tabela de Referência de Cabeçalhos
| Cabeçalho | Definido por | Propósito |
|---|---|---|
Strict-Transport-Security | helmet | Forçar HTTPS |
X-Content-Type-Options | helmet | Prevenir MIME sniffing |
Access-Control-Allow-Origin | cors | Origem permitida pelo navegador |
RateLimit-Remaining | rate-limit | Cota visível para o cliente |
Armazenamento de Limite de Taxa de Produção
import { RedisStore } from "rate-limit-redis";
import { createClient } from "redis";
const redis = createClient({ url: process.env.REDIS_URL });
await redis.connect();
const limiter = rateLimit({
store: new RedisStore({ sendCommand: (...args) => redis.sendCommand(args) }),
windowMs: 60_000,
max: 100,
});Armadilhas
- CORS
origin: *com credenciais - navegadores rejeitam essa combinação. Correção: especificar origens exatas. - Limitador de taxa antes do
trust proxy- um único bucket para todos os usuários. Correção: confie no proxy primeiro. - CSP do
helmetquebrando scripts inline - bom para APIs JSON; quebra se o Express servir HTML. Correção: desative o CSP ou configure as diretivas. - Sem limite de taxa em endpoints de autenticação - ataques de força bruta de login. Correção: limitador rigoroso em
/auth/login. - CORS não é autenticação - chamadas de servidor para servidor e
curlignoram CORS completamente. Correção: sempre valide tokens no lado do servidor. - Limite de taxa em memória com múltiplos pods - cada pod tem seu próprio contador. Correção: use o armazenamento Redis para contagem distribuída.
Alternativas
| Alternativa | Use Quando | Não Use Quando |
|---|---|---|
| Limitação de taxa de gateway de API | Kong, AWS API Gateway na frente | Implantação simples de serviço único |
| Cloudflare WAF | Proteção DDoS e contra bots na borda | API apenas interna |
Fastify @fastify/helmet | Pilha Fastify | Código-base Express |
NestJS ThrottlerModule | NestJS com limites de decorador | Express puro |
FAQs
Preciso de CORS para uma API de aplicativo móvel?
Aplicativos móveis nativos não aplicam CORS. Você ainda precisa de autenticação. CORS é importante para clientes baseados em navegador (SPA, painel de administração).
O `helmet` deve ser usado para APIs apenas JSON?
Sim. Cabeçalhos de segurança protegem contra ataques inesperados de tipo de conteúdo e melhoram as pontuações de scanners de segurança.
Qual limite de taxa é razoável?
Comece com 100 requisições/minuto por IP para API geral, 10/15min para login. Ajuste com base nos padrões de tráfego reais.
Como isento webhooks de limites de taxa?
Monte as rotas de webhook antes do limitador ou use uma função skip que verifica o caminho.
O `cors` lida com preflight?
Sim. O pacote cors responde a OPTIONS automaticamente quando configurado.
E sobre CSRF para autenticação baseada em cookie?
CORS não previne CSRF. Use csurf ou cookies SameSite com tokens de envio duplo para sessões de cookie.
Posso usar `helmet` com Fastify?
Sim, via @fastify/helmet. Os mesmos conceitos se aplicam.
Como testo cabeçalhos de segurança?
curl -sI https://api.example.com/health e verifique Strict-Transport-Security, X-Content-Type-Options, etc.
Relacionados
- Ordem de Middleware - sequência de registro
- Consciência de Proxy Reverso - confie no proxy para limites de taxa
- Noções Básicas de Segurança - postura de segurança mais ampla
- OWASP Top 10 para APIs - modelo de ameaça
- Melhores Práticas do Express - lista de verificação da seção
Versões da Stack: Esta página foi escrita para Node.js 24.18.0 (LTS Ativo), npm 10+, TypeScript 5.6+, Express 5, Fastify 5 e NestJS 11.