Segurança em APIs REST: boas práticas
APIs REST são a espinha dorsal da comunicação entre sistemas modernos, mas cada endpoint exposto representa uma superfície de ataque potencial. Para desenvolvedores, construir APIs seguras não é opcional — é requisito fundamental. Este artigo aborda as práticas essenciais para proteger suas APIs REST contra as ameaças mais comuns.
1. Autenticação e Autorização Robusta
O primeiro passo para proteger uma API é garantir que apenas usuários legítimos acessem os recursos. JSON Web Tokens (JWT) são amplamente utilizados, mas exigem cuidado na implementação.
// Exemplo de geração de JWT com RS256
const jwt = require('jsonwebtoken');
const privateKey = fs.readFileSync('private.pem');
const token = jwt.sign(
{ userId: 123, role: 'admin', scope: 'read:users write:users' },
privateKey,
{ algorithm: 'RS256', expiresIn: '15m' }
);
Boas práticas:
- Use algoritmos assimétricos (RS256, ES256) em vez de HS256
- Defina expiração curta (15-30 minutos) para tokens de acesso
- Implemente refresh tokens com rotação (cada uso gera um novo)
- Mantenha uma lista de revogação para tokens comprometidos
O controle de acesso baseado em papéis (RBAC) e escopos OAuth2 permite granularidade fina:
// Middleware de autorização com RBAC
function authorize(requiredRole, requiredScope) {
return (req, res, next) => {
const { role, scope } = req.user;
if (role !== requiredRole || !scope.includes(requiredScope)) {
return res.status(403).json({ error: 'Acesso negado' });
}
next();
};
}
2. Validação e Sanitização de Entradas
Nunca confie em dados vindos do cliente. Toda entrada deve ser validada e sanitizada antes do processamento.
// Validação com whitelist de parâmetros
const allowedParams = ['name', 'email', 'age'];
const unsafeParams = Object.keys(req.body);
unsafeParams.forEach(param => {
if (!allowedParams.includes(param)) {
delete req.body[param];
}
});
// Sanitização contra injeção
const sanitizedEmail = req.body.email.replace(/[<>"'&]/g, '');
Regras essenciais:
- Valide tipos, formatos e tamanhos máximos
- Use listas brancas (whitelist) para parâmetros permitidos
- Sanitize entradas contra SQL/NoSQL injection e command injection
- Utilize bibliotecas especializadas como validator.js ou joi
3. Proteção contra Ataques Comuns
APIs REST são alvos frequentes de XSS, CSRF e outros ataques. A configuração correta de headers HTTP é sua primeira linha de defesa.
// Configuração de headers de segurança
app.use((req, res, next) => {
res.setHeader('Content-Security-Policy', "default-src 'self'");
res.setHeader('X-Content-Type-Options', 'nosniff');
res.setHeader('X-Frame-Options', 'DENY');
res.setHeader('X-XSS-Protection', '1; mode=block');
next();
});
// CORS restritivo
const corsOptions = {
origin: ['https://meudominio.com'],
methods: ['GET', 'POST', 'PUT', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization'],
credentials: true
};
app.use(cors(corsOptions));
Para CSRF, implemente tokens anti-CSRF e utilize cookies com atributo SameSite:
// Cookie seguro com SameSite
res.cookie('session', token, {
httpOnly: true,
secure: true,
sameSite: 'strict',
maxAge: 3600000
});
4. Limitação de Taxa e Controle de Tráfego
Rate limiting protege sua API contra abusos, ataques de força bruta e scraping.
// Implementação com express-rate-limit
const rateLimit = require('express-rate-limit');
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutos
max: 100, // limite por IP
message: { error: 'Muitas requisições. Tente novamente mais tarde.' },
standardHeaders: true,
legacyHeaders: false
});
app.use('/api/', limiter);
// Limite mais restritivo para login
const loginLimiter = rateLimit({
windowMs: 60 * 60 * 1000, // 1 hora
max: 5,
skipSuccessfulRequests: true
});
app.post('/api/login', loginLimiter, loginHandler);
Estratégias adicionais:
- Implemente throttling progressivo (aumenta o tempo de espera gradualmente)
- Bloqueie temporariamente IPs após múltiplas falhas de autenticação
- Monitore padrões anômalos como bursts de requisições ou tentativas de brute force
5. Transporte Seguro e Headers de Segurança
Toda comunicação com sua API deve ocorrer exclusivamente via HTTPS com TLS 1.2 ou superior.
// Configuração de servidor HTTPS
const https = require('https');
const fs = require('fs');
const options = {
key: fs.readFileSync('server.key'),
cert: fs.readFileSync('server.cert'),
secureOptions: require('constants').SSL_OP_NO_TLSv1 | require('constants').SSL_OP_NO_TLSv1_1,
ciphers: 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256'
};
https.createServer(options, app).listen(443);
// HSTS header
app.use((req, res, next) => {
res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
next();
});
Headers obrigatórios:
- X-Content-Type-Options: nosniff
- Cache-Control: no-store para dados sensíveis
- Desative versões inseguras do protocolo (SSLv3, TLS 1.0/1.1)
6. Tratamento de Erros e Logging Seguro
Erros vazam informações valiosas para atacantes. Seja genérico nas respostas e cuidadoso nos logs.
// Tratamento global de erros
app.use((err, req, res, next) => {
const errorId = uuidv4();
// Log seguro (sem dados sensíveis)
logger.error({
errorId,
message: err.message,
stack: err.stack,
method: req.method,
path: req.path,
userId: req.user?.id
});
// Resposta genérica
res.status(500).json({
error: 'Erro interno do servidor',
errorId
});
});
Regras de logging:
- Nunca logue senhas, tokens, dados de cartão de crédito ou PII
- Use IDs de correlação para rastreamento sem expor informações críticas
- Implemente níveis de log (info, warn, error) para facilitar auditoria
7. Práticas de Versionamento e Gerenciamento de Dependências
APIs evoluem, e versões antigas podem conter vulnerabilidades conhecidas.
// Versionamento explícito
app.use('/api/v1/users', usersRouterV1);
app.use('/api/v2/users', usersRouterV2);
// Deprecação segura
app.use('/api/v1/users', (req, res, next) => {
res.setHeader('Warning', '299 - "API version 1 is deprecated. Use v2."');
next();
});
Auditoria de dependências:
// npm audit para verificar vulnerabilidades
npm audit --production
// Atualização automática com Dependabot ou Renovate
// Verificação de CVEs em bibliotecas
Mantenha um inventário de todas as dependências e estabeleça um processo para atualização imediata de correções de segurança críticas.
Conclusão
Segurança em APIs REST não é um destino, mas um processo contínuo. As práticas descritas neste artigo formam uma base sólida, mas devem ser complementadas com testes de penetração regulares, análise de vulnerabilidades e atualização constante. Lembre-se: a segurança da sua API depende do elo mais fraco da corrente — e cada desenvolvedor é responsável por fortalecer esse elo.
Referências
- OWASP REST Security Cheat Sheet — Guia completo da OWASP com práticas recomendadas para segurança em APIs REST
- JWT Best Practices (Auth0) — Artigo técnico sobre boas práticas com tokens JWT em APIs
- Express Rate Limit Documentation — Documentação oficial da biblioteca de rate limiting para Node.js
- Mozilla Web Security Guidelines — Diretrizes de segurança web da Mozilla, incluindo headers HTTP e TLS
- NPM Audit Documentation — Documentação oficial sobre auditoria de dependências com npm
- OWASP Top 10 API Security Risks — Lista oficial dos 10 principais riscos de segurança em APIs segundo a OWASP
- JSON Web Token RFC 7519 — Especificação técnica oficial do padrão JWT