Em 2019, pesquisadores de segurança descobriram que a API do Facebook expunha tokens de acesso de usuários de terceiros a qualquer aplicação que utilizasse o “Login com Facebook”. O problema permitia que aplicações maliciosas assumissem contas sem o conhecimento do usuário — afetando centenas de milhões de pessoas. No mesmo ano, a T-Mobile corrigiu uma vulnerabilidade em sua API que permitia buscar dados de clientes — nome, endereço de cobrança, tipo de conta — com apenas o número de telefone como parâmetro, sem nenhuma autenticação adicional.
Ambos os casos seguem um padrão que domina o cenário de violações de APIs: a vulnerabilidade não estava no protocolo HTTP, nos servidores, ou na infraestrutura de rede. Estava na lógica de autorização — em decisões de design que deixaram recursos expostos para quem não deveria ter acesso.
As APIs são o tecido conectivo do software moderno. Toda aplicação móvel consome APIs. Todo ecossistema de microsserviços é composto de APIs se comunicando. Toda integração entre sistemas passa por APIs. O Salt Security State of API Security Report de 2023 documenta que ataques a APIs cresceram 400% em relação ao ano anterior, e que 78% das organizações reportaram incidentes de segurança em APIs nos 12 meses anteriores à pesquisa.
A magnitude do problema levou a OWASP a criar uma lista específica para APIs — o OWASP API Security Top 10 — separada do Web Application Top 10. As vulnerabilidades são distintas: enquanto aplicações web tradicionais sofrem mais com XSS e CSRF, APIs têm um perfil de risco próprio dominado por falhas de autorização, excesso de exposição de dados, e ausência de rate limiting.
Neste artigo, você vai entender as vulnerabilidades mais críticas do OWASP API Security Top 10 com exemplos técnicos concretos, como implementar autenticação e autorização robustas, como estruturar validação de entrada e rate limiting, quais são as ferramentas de segurança específicas para APIs, e o que os casos históricos ensinam sobre onde as defesas precisam estar. Se você desenvolve, arquiteta, ou audita APIs, este guia tem o que você precisa.
O OWASP API Security Top 10: o mapa das vulnerabilidades que mais importam
A OWASP (Open Web Application Security Project) publica e atualiza o API Security Top 10 especificamente para APIs REST, GraphQL, gRPC e outras interfaces programáticas. A versão de 2023 reflete um mapeamento baseado em incidentes reais. Entender cada categoria com profundidade técnica é o ponto de partida para qualquer programa de segurança de APIs.
API1:2023 — Broken Object Level Authorization (BOLA)
BOLA é a vulnerabilidade mais prevalente em APIs e a causa direta de violações como a da T-Mobile mencionada na abertura. Ocorre quando uma API aceita identificadores de objetos (IDs de usuário, números de conta, IDs de registro) nos endpoints sem verificar se o usuário autenticado tem permissão para acessar aquele objeto específico.
O ataque é simples:
# Usuário autenticado como user_id=1001 acessando seu próprio perfil
GET /api/v1/users/1001/profile
Authorization: Bearer eyJhbGci...
# O mesmo usuário modifica o ID para acessar dados de outro usuário
GET /api/v1/users/1002/profile
Authorization: Bearer eyJhbGci...Se o servidor retorna os dados do usuário 1002 sem verificar que o token pertence ao usuário 1001, a vulnerabilidade existe. A lógica correta:
# Python — verificação correta de autorização por objeto
@app.route('/api/v1/users/<int:user_id>/profile')
@require_auth
def get_user_profile(user_id):
current_user = get_current_user_from_token(request.headers['Authorization'])
# Verifica se o usuário autenticado tem acesso ao recurso solicitado
if current_user.id != user_id and not current_user.has_role('admin'):
return jsonify({'error': 'Forbidden'}), 403
return jsonify(User.query.get_or_404(user_id).to_dict())BOLA é sistematicamente subdetectado por scanners automatizados porque a lógica de autorização é semântica — um scanner vê a resposta 200 e não sabe se aquele usuário deveria receber aquele objeto.
💡 Dica: A proteção mais eficaz contra BOLA é validar autorização no nível do objeto em cada endpoint, não apenas na camada de autenticação. Ferramentas como CASL (JavaScript), casbin (Go/Python), e OPA (Open Policy Agent) implementam autorização baseada em políticas que tornam essas verificações sistemáticas em vez de dependentes de cada desenvolvedor lembrar de adicionar o check manualmente.
API2:2023 — Broken Authentication
Falhas na implementação de autenticação incluem tokens sem expiração, algoritmos de assinatura fracos em JWTs, ausência de invalidação de tokens no logout, e proteção inadequada contra força bruta.
O ataque ao algoritmo “none” em JWTs é um exemplo clássico: algumas implementações vulneráveis aceitam um JWT onde o header declara “alg”: “none”, o que remove a assinatura e permite que qualquer payload seja aceito:
# Header malicioso — nunca aceitar "none" como algoritmo
{
"alg": "none",
"typ": "JWT"
}
# Payload com permissões elevadas
{
"sub": "user123",
"role": "admin",
"exp": 9999999999
}A verificação segura especifica explicitamente os algoritmos aceitos:
import jwt
# CORRETO — algoritmo especificado explicitamente
try:
payload = jwt.decode(
token,
SECRET_KEY,
algorithms=["HS256"], # Lista explícita — nunca deixar vazio ou aceitar "none"
options={"require": ["exp", "iat", "sub"]} # Claims obrigatórias
)
except jwt.ExpiredSignatureError:
return jsonify({'error': 'Token expired'}), 401
except jwt.InvalidTokenError:
return jsonify({'error': 'Invalid token'}), 401API3:2023 — Broken Object Property Level Authorization
Uma evolução do BOLA, essa categoria cobre situações onde o usuário pode acessar um objeto mas recebe campos que não deveria ver (excessive data exposure) ou pode modificar campos que não deveria modificar (mass assignment).
O problema de mass assignment em Node.js:
//VULNERÁVEL — aceita todos os campos do body incluindo role e isAdmin
app.put('/api/users/:id', async (req, res) => {
const user = await User.findByIdAndUpdate(
req.params.id,
req.body, // PERIGOSO: req.body pode conter { role: 'admin', isAdmin: true }
{ new: true }
);
res.json(user);
});
// CORRETO — whitelist explícita de campos modificáveis
app.put('/api/users/:id', async (req, res) => {
const allowedFields = ['name', 'email', 'phone'];
const updates = Object.fromEntries(
Object.entries(req.body).filter(([key]) => allowedFields.includes(key))
);
const user = await User.findByIdAndUpdate(req.params.id, updates, { new: true });
res.json(user);
});API4:2023 — Unrestricted Resource Consumption
APIs sem rate limiting e sem controle de recursos ficam expostas a ataques de exaustão: flooding de requisições para esgotar capacidade computacional, enumeration para descobrir dados válidos (IDs, e-mails, usernames), ou operações custosas (consultas complexas, uploads, processamento de imagens) repetidas em volume.
A ausência de rate limiting cria três vetores principais:
- DDoS econômico — atacantes geram custos excessivos de computação em cloud pay-per-use
- Credential stuffing — tentativas de login em volume sem throttling
- BOLA automation — enumerar todos os IDs possíveis para varrer dados
A implementação de rate limiting em Express com express-rate-limit:
const rateLimit = require('express-rate-limit');
const RedisStore = require('rate-limit-redis');
// Rate limit geral da API
const apiLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutos
max: 100,
message: { error: 'Too many requests, please try again later.' },
standardHeaders: true, // Retorna headers X-RateLimit-*
legacyHeaders: false,
store: new RedisStore({ /* config Redis */ }) // Funciona em múltiplas instâncias
});
// Rate limit mais restritivo para login
const loginLimiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 5, // Máximo 5 tentativas de login por 15 minutos por IP
skipSuccessfulRequests: true // Não conta logins bem-sucedidos
});
app.use('/api/', apiLimiter);
app.use('/api/auth/login', loginLimiter);API5:2023 — Broken Function Level Authorization
Enquanto BOLA trata de acesso a objetos específicos, BFLA trata de acesso a funcionalidades administrativas ou privilegiadas que o usuário não deveria conseguir executar. APIs frequentemente expõem endpoints administrativos (/admin, /internal, /management) que dependem apenas de autenticação mas não verificam se o usuário autenticado tem papel de administrador.
# Usuário comum tentando deletar outro usuário
DELETE /api/v1/admin/users/5678
Authorization: Bearer <token-de-usuario-comum>
# Se o servidor verifica apenas autenticação mas não o papel:
HTTP/1.1 200 OK
{"message": "User deleted"}A verificação correta distingue autenticação de autorização por papel:
from functools import wraps
def require_role(role):
def decorator(f):
@wraps(f)
def decorated_function(*args, **kwargs):
token = get_token_from_header()
user = validate_token(token)
if not user or role not in user.roles:
return jsonify({'error': 'Insufficient permissions'}), 403
return f(*args, **kwargs)
return decorated_function
return decorator
@app.route('/api/v1/admin/users/<int:user_id>', methods=['DELETE'])
@require_auth
@require_role('admin')
def delete_user(user_id):
# Só chega aqui se autenticado E com papel de admin
User.query.filter_by(id=user_id).delete()
return jsonify({'message': 'User deleted'}), 200⚠️ Atenção: APIs REST frequentemente expõem diferentes verbos HTTP no mesmo endpoint — GET para listar, POST para criar, DELETE para excluir. Um erro comum é implementar autorização granular para criação e deleção mas esquecer de aplicar o mesmo rigor para endpoints de listagem que retornam dados sensíveis. Cada combinação endpoint + método HTTP precisa de verificação de autorização independente.
API6:2023 — Unrestricted Access to Sensitive Business Flows
Fluxos de negócio críticos — criação de conta, compra de produto, reset de senha — podem ser abusados quando APIs não implementam controles para detectar e bloquear automação maliciosa. Um atacante que automatiza criação de contas falsas, compra de ingressos para revenda, ou coleta de informações via endpoints de busca explora fluxos legítimos de forma ilegítima.
Diferente do rate limiting puro, essa categoria exige análise comportamental: não basta limitar requisições por IP, porque atacantes distribuem através de múltiplos IPs. Detecção de bots, CAPTCHAs em fluxos sensíveis, verificação de e-mail antes de ativar funcionalidades, e análise comportamental via ferramentas como SEON e Arkose Labs são abordagens complementares.
API7:2023 — Server-Side Request Forgery (SSRF)
SSRF ocorre quando uma API aceita URLs como entrada e as busca do lado do servidor, sem validar se o destino é legítimo. Um atacante fornece URLs que apontam para serviços internos inacessíveis publicamente:
# Requisição maliciosa: a API busca a URL fornecida pelo usuário
POST /api/v1/webhooks
Content-Type: application/json
{
"callback_url": "http://169.254.169.254/latest/meta-data/iam/security-credentials/"
}No AWS, 169.254.169.254 é o endpoint de metadados de instância EC2 que retorna credenciais IAM. SSRF combinado com permissões excessivas da instância foi o vetor do comprometimento da Capital One em 2019 — um dos maiores vazamentos de dados financeiros da história, expondo dados de 100 milhões de clientes.
A mitigação envolve allowlist estrita de domínios permitidos e bloqueio de requisições para IPs privados:
import ipaddress
import socket
from urllib.parse import urlparse
def validate_webhook_url(url: str) -> bool:
"""Valida que a URL não aponta para endereços internos."""
parsed = urlparse(url)
# Apenas HTTPS permitido
if parsed.scheme != 'https':
return False
# Resolve o hostname e verifica se não é IP privado
try:
ip = socket.gethostbyname(parsed.hostname)
addr = ipaddress.ip_address(ip)
# Bloqueia IPs privados, loopback, link-local e multicast
if (addr.is_private or addr.is_loopback or
addr.is_link_local or addr.is_multicast):
return False
except (socket.gaierror, ValueError):
return False
# Apenas domínios explicitamente permitidos
ALLOWED_DOMAINS = {'example.com', 'trusted-partner.com'}
if parsed.hostname not in ALLOWED_DOMAINS:
return False
return TrueAutenticação em APIs: implementando corretamente
JWT: uso seguro e armadilhas comuns
JSON Web Tokens são o mecanismo de autenticação stateless mais usado em APIs REST. A estrutura (header.payload.signature) é bem conhecida, mas a implementação segura tem detalhes que determinam a diferença entre proteção real e proteção ilusória.
Configuração segura de JWT:
const jwt = require('jsonwebtoken');
// Geração — configuração de segurança adequada
function generateAccessToken(userId, roles) {
return jwt.sign(
{
sub: userId,
roles: roles,
iss: 'api.example.com', // Issuer — quem emitiu
aud: 'app.example.com', // Audience — para quem é destinado
iat: Math.floor(Date.now() / 1000)
},
process.env.JWT_SECRET, // Chave via variável de ambiente
{
expiresIn: '15m', // Access token de vida curta
algorithm: 'HS256' // Algoritmo explícito
}
);
}
// Verificação — algoritmo e claims explícitos
function verifyAccessToken(token) {
try {
return jwt.verify(token, process.env.JWT_SECRET, {
algorithms: ['HS256'], // Lista explícita — nunca vazia
issuer: 'api.example.com',
audience: 'app.example.com'
});
} catch (error) {
throw new Error(`Token inválido: ${error.message}`);
}
}Refresh tokens para renovação sem re-autenticação:
O padrão de access token de vida curta (15 minutos) + refresh token de vida longa (7 dias) balanceia segurança e usabilidade. O access token expira rapidamente, limitando a janela de abuso se comprometido. O refresh token fica armazenado no servidor, pode ser revogado imediatamente, e opera via cookie HttpOnly — protegido contra acesso JavaScript.
OAuth 2.0 e OpenID Connect: delegação e identidade federada
OAuth 2.0 é o protocolo de autorização que permite que APIs concedam acesso delegado — um usuário autoriza um aplicativo a acessar seus recursos em outro serviço sem revelar suas credenciais. OpenID Connect (OIDC) adiciona uma camada de autenticação sobre o OAuth 2.0, fornecendo um ID token com informações de identidade do usuário.
Para APIs que precisam suportar terceiros acessando recursos em nome de usuários, implementar OAuth 2.0 com PKCE (Proof Key for Code Exchange) é o padrão atual. PKCE elimina a necessidade de client secrets em aplicações públicas (SPAs, apps móveis) e protege contra ataques de interceptação do authorization code.
Fluxo OAuth 2.0 com PKCE:
import hashlib
import base64
import secrets
# Cliente: gera code_verifier e code_challenge
def generate_pkce_pair():
code_verifier = secrets.token_urlsafe(32) # 43-128 caracteres
code_challenge = base64.urlsafe_b64encode(
hashlib.sha256(code_verifier.encode()).digest()
).rstrip(b'=').decode()
return code_verifier, code_challenge
# Armazena code_verifier localmente
# Envia code_challenge no authorization request
# Envia code_verifier no token request — servidor verificaValidação de entrada: a defesa contra injeção e manipulação de dados
Por que toda entrada é suspeita?
APIs recebem dados de clientes que você não controla. Qualquer campo em um body JSON, parâmetro de query string, header, ou path parameter pode conter conteúdo malicioso. A defesa não é tentar detectar ataques específicos (blacklisting) — é definir precisamente o que constitui entrada válida e rejeitar tudo que não se encaixe (whitelisting).
Validação com JSON Schema em Python (Pydantic):
from pydantic import BaseModel, EmailStr, constr, validator
from typing import Optional
import re
class CreateUserRequest(BaseModel):
name: constr(min_length=2, max_length=100, regex=r'^[a-zA-ZÀ-ú\s\-]+$')
email: EmailStr
phone: Optional[constr(regex=r'^\+?[1-9]\d{1,14}$')] = None
age: int
@validator('age')
def validate_age(cls, v):
if not 18 <= v <= 120:
raise ValueError('Age must be between 18 and 120')
return v
# FastAPI usa Pydantic automaticamente — validação ocorre antes de chegar ao handler
@app.post('/api/v1/users')
async def create_user(request: CreateUserRequest):
# Se chegou aqui, request já foi validado pelo schema
return await user_service.create(request)Prevenção de SQL Injection com queries parametrizadas:
Nunca construa queries SQL concatenando strings com input do usuário. Use parâmetros de binding — o driver do banco trata o valor como dado, nunca como SQL executável:
# VULNERÁVEL — SQL injection
query = f"SELECT * FROM users WHERE email = '{user_input}'" # Não faça isso
# CORRETO — parametrizado com SQLAlchemy
from sqlalchemy import text
result = db.execute(
text("SELECT * FROM users WHERE email = :email"),
{"email": user_input} # Tratado como dado, nunca como SQL
)
# Ou usando o ORM — automaticamente seguro
user = User.query.filter_by(email=user_input).first()Sanitização para prevenção de XSS em APIs que retornam HTML:
Para APIs que retornam conteúdo que será renderizado como HTML, sanitize o output:
const DOMPurify = require('isomorphic-dompurify');
function sanitizeUserContent(content) {
return DOMPurify.sanitize(content, {
ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'p', 'br'],
ALLOWED_ATTR: [] // Sem atributos — previne event handlers
});
}Exposição de dados: o princípio da divulgação mínima
APIs frequentemente retornam mais dados do que o cliente precisa — um endpoint de listagem de usuários que retorna senhas hasheadas, tokens internos, ou campos de auditoria que apenas o sistema deveria ver. Esse padrão amplifica o impacto de qualquer comprometimento.
A abordagem correta é projetar responses explícitos em vez de serializar objetos completos:
# PERIGOSO — serializa o objeto User completo incluindo password_hash, admin_token, etc.
@app.route('/api/v1/users')
def list_users():
return jsonify([user.to_dict() for user in User.query.all()])
# CORRETO — response schema explícito com apenas os campos necessários
from dataclasses import dataclass
@dataclass
class UserPublicProfile:
id: int
name: str
email: str
created_at: str
# Sem: password_hash, admin_token, internal_notes, stripe_customer_id
@app.route('/api/v1/users')
def list_users():
users = User.query.all()
return jsonify([
UserPublicProfile(
id=u.id,
name=u.name,
email=u.email,
created_at=u.created_at.isoformat()
).__dict__
for u in users
])Segurança em APIs GraphQL
GraphQL apresenta um perfil de risco diferente de REST. A flexibilidade de queries que os clientes podem construir introduz vetores de ataque específicos:
Introspection em produção — por padrão, GraphQL expõe o schema completo via introspection queries. Atacantes usam isso para mapear todos os tipos, campos e operações disponíveis. Desabilitar introspection em produção ou restringi-la a usuários autenticados é uma medida básica.
Query depth e complexity attacks — um cliente malicioso pode construir uma query recursiva de profundidade arbitrária que provoca N+1 queries ao banco de dados e esgota recursos do servidor:
# Query maliciosa: amigos dos amigos dos amigos... infinitamente
{
user(id: "1") {
friends {
friends {
friends {
friends {
name
}
}
}
}
}
}A defesa implementa limites de profundidade e complexidade:
const { createComplexityLimitRule } = require('graphql-validation-complexity');
const depthLimit = require('graphql-depth-limit');
const server = new ApolloServer({
schema,
validationRules: [
depthLimit(5), // Máximo 5 níveis de aninhamento
createComplexityLimitRule(1000, { // Limite de complexidade calculada
scalarCost: 1,
objectCost: 10,
listFactor: 10
})
]
});Ferramentas de segurança para APIs
API Gateway: o ponto central de controle
Um API Gateway centraliza concerns transversais de segurança — autenticação, rate limiting, logging, TLS termination — em um único componente, em vez de exigir que cada serviço implemente todos esses controles independentemente.
AWS API Gateway com Lambda Authorizer implementa autenticação centralizada:
# Lambda Authorizer — valida token e retorna policy IAM
def lambda_handler(event, context):
token = event.get('authorizationToken', '').replace('Bearer ', '')
try:
payload = jwt.decode(token, JWT_SECRET, algorithms=['HS256'])
return generate_policy(
principal_id=payload['sub'],
effect='Allow',
resource=event['methodArn'],
context={'userId': payload['sub'], 'roles': ','.join(payload['roles'])}
)
except jwt.InvalidTokenError:
return generate_policy(principal_id='user', effect='Deny', resource=event['methodArn'])
def generate_policy(principal_id, effect, resource, context=None):
return {
'principalId': principal_id,
'policyDocument': {
'Version': '2012-10-17',
'Statement': [{'Action': 'execute-api:Invoke', 'Effect': effect, 'Resource': resource}]
},
'context': context or {}
}WAF específico para API: além do WAF tradicional
WAFs tradicionais foram desenhados para aplicações web que retornam HTML. APIs REST e GraphQL têm padrões de tráfego diferentes — payloads JSON, ausência de cookies de sessão em muitos casos, e modelos de autorização baseados em tokens — que requerem regras específicas.
AWS WAF com regras para APIs:
- Regras gerenciadas AWS (Core Rule Set, Known Bad Inputs) cobrem injeção básica
- Rate limiting baseado em IP e em chave de API separados por endpoint
- Geo-blocking para restringir acesso geográfico quando aplicável
- Bot control para identificar e bloquear tráfego automatizado
Cloudflare API Shield inclui schema validation automática — compara cada requisição contra um schema OpenAPI e bloqueia qualquer request que não se enquadre. Isso implementa whitelisting de forma centralizada, complementando a validação na aplicação.
Ferramentas de teste de segurança de APIs
Burp Suite com extensões específicas para API (OpenAPI/Swagger scanner, GraphQL scanner) realiza testes automatizados e manuais de vulnerabilidades. O Scanner automático identifica BOLA, injeção, exposição excessiva de dados e problemas de autenticação em APIs documentadas.
OWASP ZAP com o API Fuzzer testa endpoints com payloads de injeção e mutações de parâmetros. Para integração em pipelines CI/CD, o ZAP tem modo headless que executa como parte do processo de build.
Postman com coleções de testes de segurança permite executar verificações automatizadas em cada endpoint — verificar que endpoints retornam 401 sem token, 403 com token de usuário comum em endpoints administrativos, e que respostas não expõem campos sensíveis inesperados.
Casos históricos: o que cada violação ensina
Equifax (2017): Apache Struts + gestão de patches negligenciada
A violação da Equifax, que expôs dados de 147 milhões de pessoas, começou por uma vulnerabilidade de injeção no Apache Struts (CVE-2017-5638) — um framework web que permitia execução remota de código via header Content-Type malformado. O patch havia sido lançado dois meses antes do ataque.
A lição técnica não é apenas “aplique patches”. A profundidade do comprometimento — meses de exfiltração antes da detecção — resultou de ausência de monitoramento adequado e segmentação de rede insuficiente. Um atacante com acesso inicial a um servidor web conseguiu mover-se lateralmente por sistemas que continham dados de crédito de 147 milhões de pessoas.
O que teria limitado o dano:
- Aplicação do patch disponível dois meses antes do ataque
- Monitoramento de tráfego de saída incomum (exfiltração massiva de dados gera padrões detectáveis)
- Segmentação de rede — o servidor web não deveria ter acesso direto aos bancos de dados de crédito
- Verificação de integridade de respostas — exfiltração consistente teria mostrado volume anômalo de dados saindo
MyFitnessPal (2018): validação insuficiente + senhas com hash fraco
A Under Armour reportou em março de 2018 que a plataforma MyFitnessPal havia sido comprometida, expondo dados de 150 milhões de usuários. A violação incluiu senhas protegidas com bcrypt para a maioria dos usuários, mas uma parcela significativa usava SHA-1 — um algoritmo de hash considerado inseguro para senhas desde anos antes.
O caso ensina que segurança de APIs não é um componente isolado — a escolha de algoritmo de hash para armazenamento de senhas é uma decisão de segurança que tem impacto direto no dano causado por uma violação. Algoritmos modernos (bcrypt, Argon2, scrypt) são deliberadamente lentos para dificultar cracking mesmo após exposição dos hashes.
O que teria limitado o dano:
- Migração de SHA-1 para bcrypt/Argon2 para todos os usuários
- Validação de entrada que impedisse os vetores de injeção usados
- Detecção de acesso anômalo — 150 milhões de registros não são acessados organicamente; exfiltração desse volume gera padrões detectáveis
💡 Dica: Incidentes históricos são o melhor argumento para investir em segurança preventiva. O custo regulatório, reputacional e operacional da violação da MyFitnessPal superou em muitas vezes o custo de migrar hashes de SHA-1 para bcrypt — uma operação que um desenvolvedor competente implementa em horas. O cálculo de ROI de segurança não é “quanto custa implementar este controle” versus “quanto custa uma violação” — é a probabilidade ponderada de violação multiplicada pelo custo esperado.
Monitoramento e detecção de ameaças em APIs
O que monitorar?
Padrões de autenticação anômala — múltiplas falhas de autenticação para o mesmo usuário, autenticações bem-sucedidas de localizações ou horários incomuns, uso de tokens expirados (indica tentativa de replay).
Enumeration e BOLA attacks — um usuário que faz requisições incrementando IDs sequencialmente (/users/1, /users/2, /users/3…) está provavelmente tentando BOLA. Padrões de acesso a IDs fora da faixa esperada para aquele usuário indicam o mesmo vetor.
Volume de dados na resposta — um endpoint que normalmente retorna 1-5 KB de dados e de repente retorna 500 KB pode indicar exfiltração ou exposição excessiva de dados. Baselining do tamanho médio de resposta por endpoint e alertas para desvios significativos é uma detecção eficaz.
Rate de erros por endpoint — picos de erros 400 (bad request) frequentemente indicam fuzzing ou tentativas de injeção. Picos de erros 403 podem indicar tentativas de privilege escalation.
Logging estruturado para auditoria
{
"timestamp": "2025-06-03T14:23:45.123Z",
"request_id": "req_7f3a9c1e",
"user_id": "user_12345",
"ip": "203.0.113.45",
"method": "GET",
"path": "/api/v1/users/67890/financial-data",
"status_code": 403,
"response_time_ms": 12,
"user_agent": "Mozilla/5.0...",
"auth_method": "jwt",
"token_expires_at": "2025-06-03T14:38:00Z",
"geo": {"country": "BR", "city": "São Paulo"},
"reason": "User 12345 attempted access to user 67890 resources"
}Logs estruturados em JSON permitem consultas eficientes em sistemas como Elasticsearch, CloudWatch Logs Insights, e Splunk. Cada campo deve ser indexado para suportar as queries de detecção mais comuns.
Perguntas frequentes sobre Segurança em APIs
Autenticação responde “quem é você?” — verifica a identidade do chamador via token, chave de API, ou certificado. Autorização responde “o que você pode fazer?” — verifica se aquela identidade tem permissão para executar a operação solicitada sobre aquele recurso específico. BOLA, a vulnerabilidade mais prevalente em APIs, geralmente envolve autenticação correta mas autorização falha — o sistema verifica que você está autenticado mas não verifica se você tem permissão para acessar aquele objeto específico.
JWT é seguro quando implementado corretamente. Os problemas surgem em implementações incorretas: aceitar o algoritmo “none”, não verificar a assinatura, não validar claims como exp, iss e aud, ou armazenar JWTs em localStorage onde são vulneráveis a XSS. Implementado corretamente — algoritmo explícito, claims validadas, vida curta para access tokens, refresh tokens gerenciados via cookie HttpOnly — JWT oferece autenticação stateless robusta. Para sistemas de alta segurança, RS256 (chave assimétrica) permite que múltiplos serviços verifiquem tokens sem compartilhar a chave privada de assinatura.
A defesa em camadas começa com rate limiting por IP e por token de autenticação, o que limita automação básica. Detecção de bots (AWS WAF Bot Control, Cloudflare Bot Management, Arkose Labs) analisa padrões de comportamento para distinguir tráfego humano de automatizado. Para fluxos críticos, CAPTCHAs adicionam fricção para bots. Fingerprinting de dispositivo e análise comportamental — velocidade de digitação, padrões de mouse, sequência de navegação — identificam automação sofisticada que contorna CAPTCHAs simples. Nenhuma medida individual é 100% eficaz; a combinação cria fricção suficiente para tornar o ataque economicamente inviável para a maioria dos atacantes.
Sim, documente com OpenAPI — e não, documentação não facilita ataques de forma significativa. Atacantes motivados descobrem endpoints através de fuzzing, análise de tráfego e engenharia reversa de aplicações cliente com ou sem documentação pública. A segurança por obscuridade é uma proteção fraca que não substitui controles reais. A documentação OpenAPI tem um benefício de segurança: permite usar ferramentas como Cloudflare API Shield e AWS API Gateway para validar automaticamente que cada requisição corresponde ao schema, bloqueando payloads inesperados mesmo que o desenvolvedor não tenha previsto aquele vetor de ataque específico.
Um pipeline de segurança para APIs combina múltiplas ferramentas com papéis diferentes. SAST (análise estática de código) executa a cada commit e identifica padrões de código inseguro — uso de queries SQL sem parametrização, armazenamento de segredos em código, algoritmos criptográficos deprecated. DAST (análise dinâmica) executa em um ambiente de teste e dispara requisições maliciosas contra a API em execução — OWASP ZAP e Burp Suite Enterprise têm modos CI que se integram a GitHub Actions, GitLab CI, e Jenkins. Testes de contrato com Pact verificam que a API implementa o schema documentado corretamente. Dependency scanning (OWASP Dependency-Check, Snyk) identifica bibliotecas com CVEs conhecidos. Cada camada detecta uma classe diferente de problemas.
Segurança em APIs como disciplina de engenharia
Ao longo deste artigo, segurança em APIs revelou-se uma disciplina que vai muito além de adicionar HTTPS e um token de autenticação. As vulnerabilidades mais prevalentes — BOLA, autorização quebrada em nível de função, exposure excessiva de dados, ausência de rate limiting — são falhas de design e lógica de negócio que ferramentas automatizadas raramente detectam sozinhas.
A proteção eficaz resulta de três práticas integradas: design seguro desde o início (modelar ameaças antes de implementar endpoints, definir schemas de response explícitos, especificar políticas de autorização por objeto), implementação com controles técnicos precisos (validação de entrada via schema, queries parametrizadas, rate limiting, tokens de vida curta), e monitoramento contínuo (logs estruturados, alertas para padrões anômalos, revisão periódica com o OWASP API Top 10 como checklist).
A velocidade de desenvolvimento moderno cria pressão para cortar esses controles. O histórico de violações documentadas — Equifax, Capital One, T-Mobile, Facebook, e centenas de casos menos noticiados — demonstra que o custo de remediar uma violação supera sistematicamente o custo de implementar controles preventivos. Segurança em APIs não é custo — é investimento com retorno mensurável em risco evitado.
👉 Compartilhe este artigo com desenvolvedores, arquitetos e times de segurança que trabalham com APIs — pode ser a referência técnica que transforma discussões sobre segurança em mudanças concretas de implementação.
Uma resposta