Testes de segurança básica em APIs: validações indispensáveis

Capítulo 11

Tempo estimado de leitura: 6 minutos

+ Exercício

O que são “testes de segurança básica” em APIs

Testes de segurança básica em APIs são validações objetivas que verificam se a API se comporta de forma segura diante de entradas maliciosas ou uso indevido comum, sem exigir técnicas avançadas de pentest. O foco é confirmar que a API: (1) restringe acesso por recurso (não apenas por “estar logado”), (2) não permite enumeração de identificadores (IDOR), (3) trata entradas de forma robusta (evitando injeções comuns), (4) limita abuso por volume (rate limiting), (5) aplica CORS corretamente quando exposta a browsers e (6) não vaza dados sensíveis em headers/respostas/logs.

Esses testes são majoritariamente “casos negativos”: você tenta fazer algo que não deveria ser permitido e observa se a API responde com bloqueio, mensagens genéricas e sem detalhes internos.

Pré-requisito conceitual: dados sensíveis em trânsito e em repouso

HTTPS como base

Antes de qualquer validação, trate HTTPS como pré-requisito: credenciais, tokens e dados pessoais não devem trafegar em HTTP. Em testes, valide que:

  • O endpoint público usa https:// e não aceita downgrade para http://.
  • Requisições via HTTP (se existirem) são redirecionadas ou bloqueadas (conforme arquitetura), e nunca retornam dados sensíveis.

Checagem prática

  • Tente chamar o mesmo endpoint via HTTP e observe: não deve haver resposta com payload sensível.
  • Verifique se cookies (quando usados) têm Secure e HttpOnly (quando aplicável a apps web).

Controle de acesso por recurso (Resource-Level Authorization)

Um erro comum é validar apenas se o usuário está autenticado, mas não se ele pode acessar aquele recurso específico. Controle de acesso por recurso significa que, para cada item (pedido, conta, documento), a API verifica se o usuário tem permissão para ler/alterar aquele item.

O que validar

  • Leitura: usuário A não deve conseguir GET recursos do usuário B.
  • Alteração: usuário A não deve conseguir PATCH/PUT/DELETE recursos do usuário B.
  • Ações: endpoints de “aprovar”, “cancelar”, “reembolsar” etc. devem validar permissão por recurso e por papel.

Passo a passo prático (casos negativos)

  1. Tenha dois usuários de teste: userA e userB, cada um com seus próprios recursos (ex.: pedidos).
  2. Com credenciais de userA, crie um recurso e capture o identificador (idA).
  3. Com credenciais de userB, tente acessar o recurso de userA usando idA.
  4. Repita para operações de escrita (alterar/cancelar/excluir).
# Exemplo: userB tentando ler um recurso de userA (negativo)  GET /orders/{idA}  Authorization: Bearer <tokenUserB>

Respostas esperadas (seguras)

  • 403 Forbidden quando o recurso existe, mas o usuário não tem permissão.
  • 404 Not Found quando a estratégia é “não revelar existência” (depende do padrão do produto). O importante é consistência e não vazar detalhes.
  • Mensagem genérica, sem indicar “esse pedido pertence ao usuário X”.

Anti-padrões (sinais de falha)

  • Retornar 200 com dados de outro usuário.
  • Retornar erro detalhado indicando o dono do recurso, IDs internos, nomes de tabelas ou stack trace.

IDOR (Insecure Direct Object Reference) e enumeração de IDs

IDOR ocorre quando a API usa um identificador direto (por exemplo, /users/123, /files/abc) e não valida se o solicitante pode acessar aquele objeto. Mesmo com controle de acesso “geral”, falhas de IDOR aparecem quando a checagem por recurso é omitida em algum endpoint.

Continue em nosso aplicativo e ...
  • Ouça o áudio com a tela desligada
  • Ganhe Certificado após a conclusão
  • + de 5000 cursos para você explorar!
ou continue lendo abaixo...
Download App

Baixar o aplicativo

Como testar enumeração de IDs

O objetivo é verificar se alterar o ID na URL, query ou corpo permite acesso indevido.

Passo a passo prático

  1. Identifique endpoints com IDs previsíveis (numéricos sequenciais, UUIDs expostos, códigos curtos).
  2. Faça uma requisição válida com seu próprio ID e confirme o sucesso.
  3. Altere o ID para um valor próximo (ex.: +1, -1) ou um ID conhecido de outro usuário.
  4. Repita em endpoints de leitura e escrita.
# Exemplo: tentativa de enumeração simples  GET /accounts/1001  Authorization: Bearer <tokenUserA>  GET /accounts/1002  Authorization: Bearer <tokenUserA>

O que observar na resposta

  • Não deve haver diferença “rica” de mensagens entre “não existe” e “existe mas não é seu” que facilite enumeração.
  • Não deve retornar metadados que confirmem existência (ex.: nome, e-mail parcial, status do recurso).

Casos negativos adicionais

  • IDs em campos do corpo: { "userId": 123 } — tente trocar para outro usuário.
  • IDs em parâmetros opcionais: ?ownerId=, ?accountId=.
  • Endpoints de download: links diretos para arquivos devem exigir autorização, não apenas “URL secreta”.

Validação de input: injeções comuns em parâmetros e JSON

Validação de input em testes de API verifica se a aplicação trata entradas inesperadas sem executar comandos, sem quebrar parsing e sem retornar erros detalhados. Aqui o foco é cobrir injeções comuns e robustez de parsing, não explorar profundamente.

O que validar (visão prática)

  • Campos string não devem aceitar payloads que alterem consultas/expressões.
  • Campos numéricos devem rejeitar strings e formatos inválidos.
  • JSON malformado deve ser rejeitado com erro controlado.
  • Campos não esperados (extra fields) devem ser ignorados ou rejeitados conforme contrato, mas nunca causar comportamento inseguro.

Checklist de payloads negativos (exemplos)

Use em parâmetros de busca, filtros, ordenação e campos textuais:

  • SQL injection básica: ' OR '1'='1
  • Operadores comuns: "; DROP TABLE x; -- (apenas para validação de tratamento, não para dano)
  • NoSQL injection (quando há filtros JSON): {"$ne": null}
  • Template injection/expressões: {{7*7}}
  • Path traversal em nomes de arquivo: ../, ..\
  • JSON quebrado: {"name": "abc" (faltando fechamento)

Passo a passo prático: montar casos negativos

  1. Escolha um endpoint que receba parâmetros e/ou JSON (ex.: criação de usuário, busca, atualização).
  2. Defina um “baseline” válido (requisição que funciona).
  3. Altere um campo por vez com um payload negativo (para isolar causa).
  4. Verifique status code e corpo do erro: deve ser controlado e sem detalhes internos.
  5. Confirme que não houve efeito colateral: nenhum registro indevido criado/alterado, nenhuma permissão elevada, nenhuma consulta “aberta”.
# Baseline (válido)  POST /customers  Content-Type: application/json  { "name": "Ana", "email": "ana@example.com" }  # Negativo: tentativa de injeção em campo string  POST /customers  Content-Type: application/json  { "name": "Ana' OR '1'='1", "email": "ana@example.com" }  # Negativo: JSON malformado  POST /customers  Content-Type: application/json  { "name": "Ana", "email": "ana@example.com"

Respostas esperadas (seguras)

  • 400 Bad Request para formato inválido / JSON malformado / tipos errados.
  • 422 Unprocessable Entity
  • Mensagens genéricas e rastreáveis, sem stack trace, sem query, sem nomes de tabelas/coleções.

Anti-padrões

  • Erro 500 com stack trace, detalhes de banco, nomes de classes, caminhos de arquivo.
  • Resposta diferente que revela tecnologia interna (ex.: mensagem de driver SQL) e facilita exploração.

Rate limiting e proteção contra abuso (429)

Rate limiting reduz abuso por volume (força bruta, scraping, negação de serviço leve) limitando requisições por janela de tempo, por IP, por token, por usuário ou por rota. Em testes básicos, você valida que existe algum mecanismo e que a resposta ao exceder limite é adequada.

O que validar

  • Endpoints sensíveis (login, reset de senha, envio de código, busca pesada) têm limites mais restritivos.
  • Ao exceder o limite, a API retorna 429 Too Many Requests.
  • Se houver headers de rate limit, eles são consistentes (ex.: Retry-After quando aplicável).

Passo a passo prático

  1. Escolha um endpoint alvo (ex.: POST /auth/login ou uma rota de busca).
  2. Dispare uma sequência de requisições em curto intervalo (mesmo token/IP).
  3. Registre em qual requisição começa a bloquear.
  4. Verifique se após aguardar o tempo indicado o acesso volta ao normal.
# Pseudofluxo de teste  for i in 1..N:    POST /auth/login (credenciais inválidas)    esperar 100ms

Respostas esperadas (seguras)

  • 429 com mensagem genérica (ex.: “limite excedido”).
  • Opcional: Retry-After indicando quando tentar novamente.
  • Sem revelar regras internas detalhadas (ex.: “seu limite é 37 req/min”).

CORS quando aplicável (APIs consumidas por browser)

CORS (Cross-Origin Resource Sharing) é relevante quando a API é chamada diretamente por aplicações web no navegador. O objetivo é permitir origens confiáveis e bloquear origens não autorizadas. Em testes, você valida se a política não é permissiva demais.

O que validar

  • Não usar Access-Control-Allow-Origin: * em endpoints que aceitam credenciais (cookies/authorization via browser), quando isso for aplicável ao cenário.
  • Restringir origens a uma lista conhecida (ex.: domínio do front-end).
  • Preflight (OPTIONS) responde de forma consistente, sem abrir métodos/headers desnecessários.

Passo a passo prático

  1. Faça uma requisição simulando origem confiável com header Origin.
  2. Repita com uma origem não confiável (ex.: https://evil.example).
  3. Para rotas que exigem preflight, envie OPTIONS com Access-Control-Request-Method e Access-Control-Request-Headers.
# Preflight (exemplo)  OPTIONS /profile  Origin: https://evil.example  Access-Control-Request-Method: GET  Access-Control-Request-Headers: Authorization

Respostas esperadas (seguras)

  • Para origem não permitida: ausência de Access-Control-Allow-Origin (ou valor diferente do enviado), impedindo o browser de liberar a resposta para o script.
  • Não liberar métodos/headers além do necessário.

Política de headers sensíveis e vazamento de informações

Além do corpo da resposta, headers podem vazar informações ou permitir comportamentos inseguros. Em testes básicos, você checa se a API evita expor detalhes internos e aplica headers de segurança quando aplicável.

O que checar em respostas

  • Não expor versão/tecnologia: evitar headers como Server detalhado ou X-Powered-By (ou ao menos minimizar).
  • Não retornar tokens/segredos em headers por engano.
  • Não refletir input do usuário em headers sem sanitização.

Headers de segurança (quando a API é acessada por browsers)

  • Strict-Transport-Security (HSTS) quando o domínio é exclusivamente HTTPS.
  • Cache-Control: no-store para respostas com dados sensíveis (ex.: perfil, tokens, extratos).
  • Pragma: no-cache e Expires coerentes (legado, quando aplicável).

Passo a passo prático

  1. Escolha endpoints que retornam dados sensíveis (perfil, dados financeiros, tokens de sessão, reset de senha).
  2. Verifique headers de cache: dados sensíveis não devem ser cacheados por intermediários.
  3. Inspecione se há headers que revelam stack/infra.
VerificaçãoExemplo de riscoResultado esperado
Cache de respostaResposta com PII cacheávelCache-Control: no-store (quando aplicável)
Exposição de tecnologiaX-Powered-By: ExpressAusente ou genérico
Vazamento em erroStack trace no bodyErro controlado e genérico

Como observar “respostas seguras” em casos negativos

Ao executar testes negativos (acesso indevido, payloads maliciosos, excesso de requisições), avalie não apenas o status code, mas a qualidade do erro e o que ele revela.

Checklist de resposta segura

  • Status code coerente com o cenário (ex.: 403/404 para acesso negado, 400/422 para input inválido, 429 para limite excedido).
  • Mensagem curta e genérica, sem detalhes de implementação.
  • Sem dados sensíveis no body (IDs internos, e-mails de terceiros, tokens, segredos).
  • Sem stack trace, sem SQL/NoSQL query, sem caminhos de arquivo.
  • Consistência: o mesmo tipo de falha deve produzir o mesmo formato de erro.

Modelo de casos negativos (para você replicar)

  • Acesso por recurso: “usuário B tenta alterar recurso do usuário A”.
  • IDOR: “trocar o ID na URL e tentar ler/baixar”.
  • Input: “inserir payload de injeção em um campo por vez”.
  • Rate limit: “enviar N requisições em janela curta até obter 429”.
  • CORS: “simular Origin não permitido e validar ausência de allow”.
  • Headers: “validar no-store para dados sensíveis e ausência de headers reveladores”.

Agora responda o exercício sobre o conteúdo:

Ao testar controle de acesso por recurso (resource-level authorization), qual comportamento indica uma resposta segura quando um usuário tenta acessar um recurso que existe, mas não tem permissão para vê-lo?

Você acertou! Parabéns, agora siga para a próxima página

Você errou! Tente novamente.

Em controle de acesso por recurso, a API deve bloquear acesso indevido e evitar vazamento de informações. Respostas seguras incluem 403 quando o recurso existe sem permissão, ou 404 para não revelar existência, sempre com mensagem genérica.

Próximo capitúlo

Performance inicial e confiabilidade em testes de API: tempos, limites e resiliência

Arrow Right Icon
Capa do Ebook gratuito Testes de API: Conceitos Essenciais (REST, HTTP, Status Codes e Contratos)
73%

Testes de API: Conceitos Essenciais (REST, HTTP, Status Codes e Contratos)

Novo curso

15 páginas

Baixe o app para ganhar Certificação grátis e ouvir os cursos em background, mesmo com a tela desligada.