Andrey Escarião

Pesquisas, contos e ciência.

Testando a segurança de APIs REST, o que muda em relação a aplicação web

·

·

5 min de leitura

Muita gente testa API como se fosse site, e é por isso que tanta falha grave de API passa despercebida. O navegador esconde a maior parte do que uma API faz, e a interface bonita dá a falsa sensação de que a lógica por trás foi protegida junto.

Não foi. A API é a porta dos fundos que ficou com a fechadura mais simples.

Por que API é diferente

Aplicação web tradicional entrega tela pronta. A API entrega dado cru, e presume que o cliente vai se comportar. Essa presunção é a origem de quase toda falha específica de API.

A metodologia geral de teste, que descrevi em Metodologia de teste de invasão em aplicações web, continua valendo: escopo, reconhecimento, mapeamento, exploração controlada, relatório. O que muda são as classes de falha que você caça na fase de exploração.

Passo 1: obter o mapa da API

Antes de testar, você precisa saber quais rotas existem. A melhor fonte é a documentação da própria API, quando exposta:

curl -sS https://api.alvo.com.br/swagger.json | python -m json.tool | grep -E '"(get|post|put|delete)"' -i
curl -sSI https://api.alvo.com.br/v1/ | grep -i 'link\|allow'

Documentação de API exposta sem autenticação já é achado por si só, porque entrega o mapa completo da superfície para qualquer um.

Passo 2: a falha número um, controle de acesso por objeto

É a falha mais comum e mais grave em API. Acontece quando a API confia no identificador que o cliente envia, sem confirmar se aquele cliente tem direito àquele objeto.

# autenticado como usuario 1001, tento ler o pedido de outro
curl -sS -H "Authorization: Bearer TOKEN_DO_1001" \
  https://api.alvo.com.br/v1/pedidos/1002

Se a resposta traz o pedido de outro usuário, você acabou de encontrar acesso indevido a dado alheio. O teste é trivial e o impacto é enorme: costuma significar que qualquer cliente lê os dados de todos os outros trocando um número.

Passo 3: autorização em nível de função

Parecido, mas sobre a ação em vez do objeto. Um usuário comum não deveria conseguir executar operação administrativa, mesmo que a interface não mostre o botão.

# a tela nao oferece, mas a rota existe?
curl -sS -X DELETE -H "Authorization: Bearer TOKEN_COMUM" \
  https://api.alvo.com.br/v1/usuarios/55

Esconder a função na interface não é controle de acesso. Se a rota responde à requisição direta, o controle está apenas no front-end, que não controla nada.

Passo 4: excesso de dado na resposta

API que devolve o objeto inteiro e deixa o cliente escolher o que exibir é uma armadilha silenciosa. A tela mostra o nome; a resposta traz também documento, telefone e endereço.

curl -sS -H "Authorization: Bearer TOKEN" \
  https://api.alvo.com.br/v1/perfil/1001 | python -m json.tool

Leia a resposta completa, campo por campo, e compare com o que a tela usa. Todo campo a mais é vazamento esperando por quem olhar o tráfego, e ninguém precisa nem forçar nada para obtê-lo.

Passo 5: ausência de limite de requisições

API sem limite convida a dois abusos: força bruta em autenticação e coleta em massa de dados. Teste com cautela, porque volume alto pode caracterizar negação de serviço, que costuma estar fora do escopo.

# poucas repeticoes, so para verificar SE existe limite
for i in $(seq 1 15); do
  curl -s -o /dev/null -w "%{http_code}\n" \
    https://api.alvo.com.br/v1/login -d '{"user":"x","pass":"y"}'
done

Se as quinze respostas vierem iguais, sem nenhum sinal de bloqueio, provavelmente não há limite. Registre o indício e pare. Confirmar exaustivamente já seria o abuso que você veio testar se é possível.

Passo 6: o token

O token de autenticação merece exame próprio. Perguntas que rendem:

  • Ele expira? Token que vale para sempre é senha que nunca troca.
  • O que ele carrega? Alguns embutem dados no próprio token; leia o que está lá.
  • O servidor valida a assinatura de verdade, ou aceita token com assinatura ausente?
  • Trocar um identificador dentro do token muda o que ele acessa?

Token é a chave da API inteira. Uma falha na forma como ele é emitido ou validado costuma valer mais que todas as outras juntas.

Relatar com a requisição inteira

Achado de API sem a requisição completa é impossível de reproduzir. Cada item do relatório precisa trazer o método, a rota, os cabeçalhos relevantes, o corpo e a resposta obtida, para que a equipe consiga repetir exatamente.

E vale a regra de sempre: prova sem dano. Demonstre que leu o dado de outro usuário com um registro, não com a base inteira. O objetivo é evidenciar a falha, não exercê-la.