API4:2023 Unrestricted Resource Consumption
Agentes Ameaça/Vetores Ataque | Falha Segurança | Impactos |
---|---|---|
Específico da API : Abuso Moderado | Prevalência Predominante : Deteção Fácil | Técnico Grave : Específico Negócio |
A exploração requer pedidos simples de API. Múltiplos pedidos concorrentes podem ser feitos a partir de um único computador local ou utilizando recursos de computação em nuvem. A maioria das ferramentas automatizadas disponíveis são projetadas para causar DoS (Negação de Serviço) através de altas cargas de tráfego, afetando a taxa de serviço das APIs. | É comum encontrar APIs que não limitam as interações do cliente ou o consumo de recursos. Pedidos de API elaborados, como aqueles que incluem parâmetros que controlam o número de recursos a serem retornados e realizam análises de estado/tempo/comprimento de resposta, devem permitir a identificação do problema. O mesmo vale para operações em quantidade. Embora os agentes maliciosos não tenham visibilidade sobre o impacto nos custos, isso pode ser inferido com base no modelo de negócios/preços dos fornecedores de serviços (e.g. fornecedor de nuvem). | A exploração pode levar a uma Negação de Serviço (DoS) devido à escassez de recursos, mas também pode resultar num aumento dos custos operacionais, como os relacionados à infraestrutura devido à maior exigência de CPU, aumento das necessidades de armazenamento em nuvem, etc. |
A API é vulnerável?
Para atender aos pedidos feitos à API, são necessários recursos como largura de banda de rede, CPU, memória e armazenamento. Às vezes, os recursos necessários são disponibilizados por provedores de serviços por meio de integrações de API e são pagos por pedido, como o envio de emails/SMS/chamadas telefónicas, validação biométrica, etc.
Uma API é vulnerável se pelo menos um dos seguintes limites estiver ausente ou definido inadequadamente (e.g. muito baixo/alto):
- Tempos limite de execução
- Memória máxima alocável
- Número máximo de descritores de ficheiro
- Número máximo de processos
- Tamanho máximo de upload de ficheiro
- Número de operações a serem realizadas num único pedido do cliente da API (e.g. agrupamento GraphQL)
- Número de registros por página a serem retornados num único pedido-resposta
- Limite de gastos de provedores de serviços terceiros
Exemplos de Cenários de Ataque
Cenário #1
Uma rede social implementou um mecanismo de "recuperar senha" através da verificação por SMS, permitindo que o utilizador receba um token de uso único via SMS para redefinir a sua senha.
Uma vez que o utilizador clica em "recuperar senha", é feita uma chamada API a partir do navegador do utilizador para a API de back-end:
POST /initiate_forgot_password
{
"step": 1,
"user_number": "6501113434"
}
Em seguida, nos bastidores, é feita uma chamada API do back-end para uma API de terceiros que se encarrega da entrega do SMS:
POST /sms/send_reset_pass_code
Host: willyo.net
{
"phone_number": "6501113434"
}
O fornecedor de terceiros, Willyo, cobra $0.05 por este tipo de chamada.
Um atacante escreve código que envia a primeira chamada API dezenas de milhares de vezes. O back-end prossegue e solicita à Willyo que envie dezenas de milhares de mensagens de texto, levando a empresa a perder milhares de dólares em questão de minutos.
Cenário #2
Um endpoint de API GraphQL permite que o utilizador carregue uma foto de perfil.
POST /graphql
{
"query": "mutation {
uploadPic(name: \"pic1\", base64_pic: \"R0FOIEFOR0xJVA…\") {
url
}
}"
}
Uma vez concluído o carregamento, a API gera múltiplas miniaturas com diferentes tamanhos com base na imagem carregada. Esta operação gráfica consome muita memória do servidor.
A API implementa uma proteção tradicional de limitação de quantidade de pedidos - um utilizador não pode aceder ao endpoint GraphQL demasiadas vezes num curto período de tempo. A API também verifica o tamanho da imagem carregada antes de gerar as miniaturas para evitar o processamento de imagens demasiado grandes.
Um atacante pode facilmente contornar esses mecanismos, aproveitando a natureza flexível do GraphQL:
POST /graphql
[
{"query": "mutation {uploadPic(name: \"pic1\", base64_pic: \"R0FOIEFOR0xJVA…\") {url}}"},
{"query": "mutation {uploadPic(name: \"pic2\", base64_pic: \"R0FOIEFOR0xJVA…\") {url}}"},
...
{"query": "mutation {uploadPic(name: \"pic999\", base64_pic: \"R0FOIEFOR0xJVA…\") {url}}"},
}
Como a API não limita o número de vezes que a operação uploadPic
pode ser
tentada, a chamada levará ao esgotamento da memória do servidor e à negação de
serviço (Denial of Service).
Cenário #3
Um prestador de serviços permite que os clientes descarreguem ficheiros arbitrariamente grandes através da sua API. Estes ficheiros são mantidos em armazenamento de objetos na nuvem e não mudam com frequência. O prestador de serviços depende de um serviço de cache para melhorar a velocidade do serviço e manter o consumo de largura de banda baixo. O serviço de cache apenas armazena ficheiros até 15GB.
Quando um dos ficheiros é atualizado, o seu tamanho aumenta para 18GB. Todos os clientes do serviço começam imediatamente a descarregar a nova versão. Como não havia alertas de custo de consumo, nem um limite máximo de custo para o serviço de nuvem, a fatura mensal seguinte aumenta de 13 dólares, em média, para 8 mil dólares.
Como Prevenir
- Utilize uma solução que facilite a limitação de memória, CPU, número de reinícios, descritores de ficheiros e processos, como Containers / Código Serverless (e.g. Lambdas).
- Defina e force um tamanho máximo de dados em todos os parâmetros e conteúdos de entrada, como comprimento máximo para strings, número máximo de elementos em arrays e tamanho máximo de ficheiro para upload (independentemente de ser armazenado localmente ou na nuvem).
- Implemente um limite de frequência com que um cliente pode interagir com a API dentro de um período temporal definido (rate limiting).
- A limitação de pedidos deve ser ajustada com base nas necessidades do negócio. Alguns endpoints da API podem exigir políticas mais rigorosas.
- Limite/controle quantas vezes ou com que frequência um único cliente/utilizador da API pode executar uma única operação (e.g. validar um OTP ou solicitar a recuperação de senha sem visitar o URL de uso único).
- Adicione validação adequada no lado do servidor para parâmetros da query string e do corpo do pedido, especificamente aqueles que controlam o número de resultados a serem retornados na resposta.
- Configure limites de gastos para todos os fornecedores de serviços/integrações de API. Quando não for possível definir limites de gastos, devem ser configurados alertas de faturamento.
Referências
OWASP
- "Availability" - Web Service Security Cheat Sheet
- "DoS Prevention" - GraphQL Cheat Sheet
- "Mitigating Batching Attacks" - GraphQL Cheat Sheet