Segurança de APIs REST
A aula aborda práticas essenciais de segurança para APIs REST, incluindo autenticação, rate limiting, validação de entrada e gerenciamento de segredos, com exemplos práticos e recomendações para implementação segura.
APIs REST são fundamentais para a comunicação entre sistemas modernos, mas sua exposição pública as torna alvos frequentes de ataques. Garantir a segurança de uma API envolve múltiplas camadas de proteção, desde a autenticação de usuários até o controle de acesso e a proteção contra abusos. Nesta aula, exploraremos quatro pilares críticos: autenticação, rate limiting, validação de entrada e gerenciamento de segredos.
Cada um desses tópicos desempenha um papel vital na defesa contra ameaças comuns, como ataques de força bruta, injeção de dados, exaustão de recursos e vazamento de informações sensíveis. Ao final, você terá um guia prático para implementar essas medidas em suas próprias APIs.
Autenticação
Autenticação é o processo de verificar a identidade de um cliente que faz uma requisição à API. Sem ela, qualquer pessoa poderia acessar recursos protegidos. Os métodos mais comuns incluem tokens JWT (JSON Web Tokens), chaves de API e OAuth 2.0. O JWT é amplamente utilizado por ser stateless: o servidor não precisa armazenar sessões, pois as informações do usuário e a assinatura digital estão contidas no token.
Para implementar autenticação segura, sempre utilize HTTPS para evitar interceptação de credenciais. Armazene tokens de forma segura no cliente (por exemplo, em cookies httpOnly ou em memória) e nunca exponha segredos em URLs ou logs. Além disso, estabeleça um tempo de expiração curto para tokens e implemente refresh tokens para renovação segura.
Exemplo de fluxo de autenticação com JWT:
1. Cliente envia credenciais (usuário/senha) para /api/login.
2. Servidor valida as credenciais e gera um JWT com payload (user_id, role, exp).
3. Servidor retorna o JWT no corpo da resposta ou em um cookie seguro.
4. Cliente envia o JWT no header Authorization: Bearer <token> em requisições subsequentes.
5. Servidor verifica a assinatura e a expiração do JWT antes de processar a requisição.
Boas práticas: use algoritmos de assinatura fortes (HS256 ou RS256), evite incluir informações sensíveis no payload e sempre valide a emissão (iss) e audiência (aud) do token.
Rate Limiting
Rate limiting controla o número de requisições que um cliente pode fazer em um determinado período. Isso protege a API contra abusos, como ataques de força bruta, DDoS e uso excessivo que pode sobrecarregar o servidor. Estratégias comuns incluem limite por IP, por token de autenticação ou por chave de API.
Implementações típicas usam algoritmos como Token Bucket, Leaky Bucket ou Sliding Window. O servidor retorna códigos de status HTTP 429 (Too Many Requests) quando o limite é excedido, juntamente com headers informativos como Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining e X-RateLimit-Reset.
Exemplo de configuração de rate limiting em um gateway de API (pseudo-código):
# Configuração: 100 requisições por minuto por usuário
rate_limit = RateLimit(requests=100, window=60, key='user_id')
# Middleware de rate limiting
app.use(rate_limit.middleware)
# Rota protegida
@app.route('/api/recurso')
def recurso():
return {'dados': 'exemplo'}
Boas práticas: defina limites diferentes para endpoints críticos (ex.: login) versus endpoints de leitura. Use cache distribuído (Redis) para rate limiting em ambientes escaláveis. Sempre informe o cliente sobre o limite e o tempo de reset.
Input Validation
Validação de entrada é a primeira linha de defesa contra ataques de injeção (SQL, NoSQL, OS command, etc.) e dados malformados. Nunca confie em dados fornecidos pelo cliente: todo input deve ser verificado quanto ao tipo, formato, tamanho e conteúdo esperado. Utilize bibliotecas de validação robustas e evite construir consultas ou comandos concatenando strings.
Exemplo de validação de entrada em uma API REST (pseudo-código):
# Validação de campo 'email' em requisição POST
import re
def validate_email(email):
if not re.match(r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$', email):
raise ValidationError('Email inválido')
if len(email) > 254:
raise ValidationError('Email muito longo')
return email
Além de validação, use prepared statements ou ORMs para consultas a bancos de dados e escape adequado para saídas. Nunca exponha detalhes internos do sistema em mensagens de erro: retorne respostas genéricas como "Dados inválidos" e registre logs detalhados internamente.
Secrets Management
Gerenciamento de segredos envolve proteger informações sensíveis como chaves de API, senhas de banco de dados, tokens de autenticação e certificados. Nunca hardcode segredos no código-fonte ou em arquivos de configuração versionados. Utilize ferramentas como cofres de segredos (HashiCorp Vault, AWS Secrets Manager, Azure Key Vault) ou variáveis de ambiente criptografadas.
Boas práticas: rotacione segredos regularmente, restrinja o acesso com base no princípio do menor privilégio, e use criptografia em repouso e em trânsito. Em ambientes de desenvolvimento, use segredos mock ou locais, mas nunca compartilhe segredos de produção em repositórios.
Exemplo de uso de variáveis de ambiente para segredos (pseudo-código):
import os
DB_PASSWORD = os.environ.get('DB_PASSWORD')
if not DB_PASSWORD:
raise Exception('DB_PASSWORD não definido')
# Conectar ao banco com a senha segura
Para ambientes em contêiner, evite passar segredos como variáveis de ambiente se o sistema de orquestração não for seguro; prefira montar volumes com segredos ou usar sidecars dedicados.
Boas Práticas e Observações Finais
Além dos pilares abordados, considere implementar logging e monitoramento de segurança, usar firewalls de API (WAF) e realizar testes de penetração regularmente. A segurança é um processo contínuo: mantenha-se atualizado sobre novas vulnerabilidades e atualize suas dependências. Documente claramente as políticas de segurança para consumidores da API, incluindo limites de taxa e métodos de autenticação suportados.
Referências
- OWASP Top 10 - 2021
- Introduction to JSON Web Tokens
- HTTP Authentication (RFC 7235)
- Google Cloud API Rate Limiting
- OWASP Input Validation Cheat Sheet
- HashiCorp Vault: Static Secrets
Exercícios
- Explique por que é importante usar HTTPS em APIs que implementam autenticação via JWT.
- Descreva como o rate limiting pode ajudar a prevenir ataques de força bruta em endpoints de login.
- Cite três tipos de ataque que a validação de entrada pode prevenir e dê um exemplo de cada.
- Por que não se deve hardcodear segredos no código-fonte? Mencione pelo menos duas alternativas seguras.
- Projete um cenário onde a falta de rate limiting em uma API pública pode levar a um ataque de negação de serviço (DoS). Como você mitigaria?