Segurança em APIs REST: além do básico de autenticação
1. Controle de Acesso Granular: Autorização por Escopo e Recursos
1.1. OAuth 2.0 e OpenID Connect: escopos, claims e validação de tokens JWT
Autenticação básica (usuário/senha) é insuficiente para APIs modernas. O OAuth 2.0 com OpenID Connect permite controle granular via escopos e claims JWT.
Exemplo de token JWT com escopos:
{
"iss": "https://auth.example.com",
"sub": "user_12345",
"aud": "api.example.com",
"exp": 1719000000,
"iat": 1718913600,
"scope": "read:orders write:orders admin:users",
"claims": {
"role": "manager",
"department": "finance",
"region": "us-east"
}
}
Validação de token em middleware:
function validateToken(req, res, next) {
const token = req.headers.authorization?.split(' ')[1]
if (!token) return res.status(401).json({ error: 'Token ausente' })
try {
const decoded = jwt.verify(token, PUBLIC_KEY, { algorithms: ['RS256'] })
// Verificar escopo específico
if (!decoded.scope.includes('read:orders')) {
return res.status(403).json({ error: 'Escopo insuficiente' })
}
req.user = decoded
next()
} catch (err) {
return res.status(401).json({ error: 'Token inválido' })
}
}
1.2. RBAC vs. ABAC em APIs REST
RBAC (Role-Based Access Control) atribui permissões por cargo, enquanto ABAC (Attribute-Based Access Control) avalia atributos do usuário, recurso e ambiente.
Exemplo de política ABAC:
POLICY: Acesso a relatórios financeiros
IF user.department == "finance"
AND user.region == resource.region
AND time.between("09:00", "18:00")
THEN ALLOW read
ELSE DENY
Implementação de RBAC simples:
const roles = {
admin: ['read:any', 'write:any', 'delete:any'],
manager: ['read:orders', 'write:orders'],
viewer: ['read:orders']
}
function authorize(role, action) {
return roles[role]?.includes(action) || false
}
1.3. Gateways de API e PDP (Policy Decision Point)
Gateways centralizam políticas de segurança, delegando decisões a um PDP externo.
Arquitetura com PDP:
Cliente → Gateway API → PDP (Policy Decision Point) → Serviço
↓
Policy Enforcement Point (PEP)
Exemplo de requisição ao PDP:
POST /pdp/authorize
{
"subject": { "id": "user_123", "role": "manager" },
"resource": { "type": "order", "id": "ORD-456" },
"action": "read",
"context": { "ip": "192.168.1.10", "time": "2025-06-20T14:30:00Z" }
}
RESPONSE: { "decision": "PERMIT", "obligations": ["log_access"] }
2. Proteção contra Injeção e Manipulação de Dados
2.1. Validação de entrada e sanitização
Injeções ocorrem quando dados não confiáveis são interpretados como comandos.
Exemplo de SQL Injection prevenida:
// VULNERÁVEL
query = "SELECT * FROM users WHERE id = " + req.params.id
// SEGURO (parametrização)
query = "SELECT * FROM users WHERE id = $1"
result = db.execute(query, [req.params.id])
Sanitização para NoSQL:
function sanitizeMongoQuery(input) {
// Remove operadores $ perigosos
const dangerous = ['$where', '$ne', '$gt', '$regex']
return JSON.parse(JSON.stringify(input), (key, value) => {
if (dangerous.includes(key)) return undefined
return value
})
}
2.2. Mass Assignment Protection
Evite que usuários modifiquem campos não autorizados via requisições bulk.
DTOs específicos por operação:
// DTO para criação de usuário
{
"allowed_fields": ["name", "email", "password"]
}
// DTO para atualização de perfil
{
"allowed_fields": ["name", "phone", "avatar_url"]
"blocked_fields": ["role", "is_admin", "balance"]
}
Implementação de whitelisting:
function filterFields(body, allowedFields) {
const filtered = {}
for (const field of allowedFields) {
if (body[field] !== undefined) {
filtered[field] = body[field]
}
}
return filtered
}
// Uso no endpoint
app.post('/users', (req, res) => {
const safeBody = filterFields(req.body, ['name', 'email', 'password'])
// Processa apenas campos seguros
})
2.3. Rate Limiting e Throttling inteligente
Proteja contra força bruta e DDoS com limites adaptativos.
Configuração de rate limiting:
// Por endpoint sensível
POST /api/login → 5 requisições/minuto por IP
POST /api/reset-password → 3 requisições/hora por email
GET /api/public → 100 requisições/minuto por IP
// Throttling adaptativo
if (error_rate > 0.1) {
reduce_limit_by(50%)
}
if (suspicious_pattern_detected) {
block_for(15, 'minutes')
}
3. Segurança na Camada de Transporte e Criptografia
3.1. TLS 1.3 obrigatório
Configuração mínima para APIs modernas:
# Nginx - cipher suites seguras
ssl_protocols TLSv1.3;
ssl_ciphers TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256;
ssl_prefer_server_ciphers on;
# HSTS
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
3.2. Criptografia de payload sensível
Criptografia de campo vs. registro:
// Criptografia de campo (dados específicos)
{
"user_id": "usr_789",
"encrypted_ssn": "aes_gcm_encrypted_base64_data",
"name": "João Silva" // campo não sensível
}
// Criptografia de registro (todo o payload)
{
"encrypted_payload": "aes_gcm_encrypted_base64_data",
"iv": "base64_iv",
"tag": "base64_auth_tag"
}
3.3. mTLS para autenticação mútua
Ideal para comunicação entre microserviços:
// Configuração de cliente mTLS
curl --cert client.crt --key client.key \
--cacert ca.crt \
https://service.internal/api/data
// Verificação no servidor
if (!client_certificate.valid ||
!client_certificate.cn in allowed_services) {
return 403 Forbidden
}
4. Prevenção de Ataques Comuns em APIs REST
4.1. CSRF e CORS configurados corretamente
CORS restritivo:
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400
Proteção CSRF para APIs baseadas em cookie:
// Gerar token CSRF
csrf_token = crypto.randomBytes(32).toString('hex')
set_cookie('csrf_token', csrf_token, { httpOnly: true, sameSite: 'strict' })
// Validar em mutações
if (req.headers['x-csrf-token'] !== get_cookie('csrf_token')) {
return 403 Forbidden
}
4.2. Proteção contra IDOR e Path Traversal
IDOR prevention:
// Em vez de depender do ID enviado
GET /api/orders/ORD-123
// Verificar propriedade do recurso
function getOrder(orderId, userId) {
const order = db.orders.findById(orderId)
if (order.user_id !== userId) {
throw new ForbiddenError('Acesso negado')
}
return order
}
Path traversal prevention:
function sanitizePath(userInput) {
// Remove caracteres de path traversal
const safe = userInput.replace(/\.\.\//g, '')
.replace(/\.\.\\/g, '')
.replace(/\0/g, '')
// Garante que está dentro do diretório permitido
if (safe.includes('/') || safe.includes('\\')) {
throw new Error('Caminho inválido')
}
return safe
}
4.3. Mitigação de ataques de Replay com Nonce e Timestamp
Implementação de nonce:
// Cliente inclui nonce e timestamp
{
"nonce": "a1b2c3d4e5f6",
"timestamp": 1718913600,
"data": { ... }
}
// Servidor valida
function validateNonce(nonce, timestamp) {
// Verifica se timestamp é recente (5 minutos)
if (Math.abs(Date.now()/1000 - timestamp) > 300) {
return false
}
// Verifica se nonce já foi usado
if (redis.exists(`nonce:${nonce}`)) {
return false
}
// Marca nonce como usado
redis.set(`nonce:${nonce}`, 'used', 'EX', 300)
return true
}
5. Logging, Monitoramento e Resposta a Incidentes
5.1. Logging seguro
O que registrar e o que nunca registrar:
// NUNCA registrar
senhas, tokens JWT, números de cartão, SSN/CPF, chaves de API
// SEMPRE registrar
correlation_id, user_id (anonimizado), endpoint, método HTTP,
status code, timestamp, IP (anonimizado), user-agent
Exemplo de log seguro:
{
"correlation_id": "req_abc123",
"user_id": "usr_***789", // anonimizado
"method": "POST",
"endpoint": "/api/orders",
"status": 201,
"ip": "192.168.1.***", // anonimizado
"timestamp": "2025-06-20T14:30:00Z",
"duration_ms": 45
}
5.2. Auditoria com correlation IDs
// Gerar correlation ID no gateway
function generateCorrelationId() {
return `req_${uuid.v4()}`
}
// Propagar para todos os serviços
X-Correlation-ID: req_abc123-def456-ghi789
5.3. Detecção de anomalias
Regras de detecção automatizada:
// Anomalias comuns
if (requests_per_minute > threshold * 10) → possível DDoS
if (error_rate > 0.2) → possível ataque ou falha
if (same_user_agent + different_ips) → scraping
if (sequential_ids + unauthorized_access) → IDOR attempt
// Resposta automatizada via webhook
if (anomaly_detected) {
webhook.send({
type: 'security_alert',
action: 'block_ip',
ip: attacker_ip,
duration: 3600
})
}
6. Gestão de Segredos e Ciclo de Vida de Credenciais
6.1. Armazenamento seguro com cofres de segredos
// HashiCorp Vault - exemplo de acesso
vault write secret/api/production \
api_key="sk_live_abc123" \
db_password="s3cur3P@ss"
// Aplicação lê do vault, não do código
api_key = vault.read('secret/api/production').data.api_key
6.2. Rotação automática de credenciais
// Política de rotação
- Tokens de acesso: expiração em 15 minutos
- Tokens de refresh: expiração em 7 dias
- Chaves de API: rotação a cada 90 dias
- Certificados mTLS: renovação a cada 30 dias
// Rotação automática
if (token.exp < now + 300) { // 5 minutos antes de expirar
new_token = refreshToken(refresh_token)
update_stored_token(new_token)
}
6.3. Revogação de tokens: blocklists vs. allowlists
// Blocklist (lista negra) - para revogação imediata
redis.sadd('token:blocklist', token_jti)
redis.expire('token:blocklist', 86400) // 24 horas
// Allowlist (lista branca) - para controle granular
redis.sadd('user:123:active_tokens', token_jti)
if (!redis.sismember('user:123:active_tokens', token_jti)) {
return 401 Unauthorized
}
7. Segurança em Documentação e Headers HTTP
7.1. Headers de segurança essenciais
Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted.cdn.com
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=()
7.2. Exposição controlada de metadados
// Nunca expor
X-Powered-By: Express 4.18.2
Server: Apache/2.4.41 (Ubuntu)
X-Debug: true
// Configuração segura
app.disable('x-powered-by')
helmet() // Remove headers informativos
7.3. Documentação segura de APIs
Exemplo de OpenAPI com segurança explícita:
openapi: 3.0.0
info:
title: API de Pedidos
version: 1.0.0
description: "Documentação segura - requer autenticação"
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
description: "Token JWT com escopos: read:orders, write:orders"
paths:
/orders:
get:
summary: Listar pedidos
security:
- bearerAuth: [read:orders]
responses:
'200':
description: Lista de pedidos
'403':
description: Escopo insuficiente
Referências
-
OWASP API Security Top 10 (2023) — Lista oficial das 10 principais vulnerabilidades em APIs REST, com descrições detalhadas e exemplos de mitigação.
-
Auth0: OAuth 2.0 and OpenID Connect in Plain English — Documentação oficial sobre fluxos OAuth 2.0, escopos e validação de tokens JWT.
-
Mozilla Web Security Guidelines — Guia completo de headers de segurança HTTP, configuração de TLS e práticas recomendadas para APIs.
-
HashiCorp Vault Documentation: Secrets Management — Documentação oficial sobre armazenamento seguro de segredos, rotação de credenciais e políticas de acesso.
-
NIST SP 800-63B: Digital Identity Guidelines — Padrão governamental para autenticação, autorização e gestão de credenciais em sistemas digitais.
-
Cloudflare: What is mTLS? — Guia prático sobre autenticação mútua TLS, configuração e casos de uso em APIs.
-
Stripe API Security Best Practices — Documentação técnica sobre rate limiting, proteção contra IDOR e logging seguro em APIs de produção.