Avançar para o conteúdo principal
BlogueComputaçãoDefenda seu servidor GraphQL contra o consumo excessivo de recursos

Defenda seu servidor GraphQL contra o consumo excessivo de recursos

Ilustração de um gráfico de barras com muitos pontos de dados, criando um aspeto ondulado com texto: Defenda seu servidor GraphQL contra o consumo excessivo de recursos.

O GraphQL oferece a flexibilidade de solicitar exatamente os recursos e atributos de que você precisa - nada mais, nada menos. Isso é diferente do REST, que muitas vezes busca dados demais ou de menos. Essa precisão torna o GraphQL altamente eficiente. Além disso, o GraphQL oferece maneiras padrão de lidar com a paginação, aumentando ainda mais sua flexibilidade. No entanto, os utilizadores maliciosos podem explorar estas funcionalidades do GraphQL, o que pode representar riscos significativos para a estabilidade do seu servidor.

Neste blogue, vamos explorar como a flexibilidade do GraphQL pode ser virada contra si. Estamos nos concentrando especificamente em uma vulnerabilidade destacada pelo Top 10 de segurança de API da OWASP: consumo irrestrito de recursos. Também discutiremos etapas práticas para proteger seus sistemas contra esse tipo de abuso.

A resposta do GraphQL para over-fetching e under-fetching

O GraphQL foi projetado em parte para resolver os problemas de busca excessiva que normalmente encontramos com o REST. Por exemplo, vamos considerar um banco de dados de comércio eletrônico padrão com usuários, produtos e pedidos. Imagine a necessidade de buscar o valor total em dólares de um pedido dado no ID do pedido. Com REST, esse pedido GET para /orders/17 iria buscar não apenas o valor em dólares, mas também o seguinte:

  • dados da encomenda
  • informações de faturação
  • informações de envio
  • quantidades de produtos
  • fiscal
  • estado da encomenda
  • ... e mais

Isso é um exagero.

Com o REST, também se depara com a sub-busca, quando é necessário reunir dados associados de vários recursos. Imagine que pretende apresentar um resumo, com a data e o estado de uma encomenda, os nomes e as descrições de todos os produtos da encomenda e o nome e o e-mail do utilizador que efectuou a encomenda. Para o fazer, teria de enviar vários pedidos:

  • GET /encomendas/17
  • GET /produtos/1662527
  • GET /produtos/9914188
  • GET /produtos/3750021
  • GET /produtos/7557109
  • GET /produtos/6081142
  • GET /usuários/3314

O GraphQL foi a resposta para essas deficiências do REST. É possível consultar exatamente o que você precisa, em recursos associados. Para realizar o que foi dito acima, seu GraphQL pode ter a seguinte aparência:

query {
  order(id: "17") {
    date
    status
    products {
      name
      description
    }
    user {
      name
      email
    }
  }
}

É tão simples e flexível! No entanto, este nível de flexibilidade também significa que um utilizador malicioso pode deliberadamente obter dados em excesso.

Abusar da flexibilidade das consultas

A sintaxe de consulta do GraphQL permite que você execute várias consultas na mesma solicitação. Poderíamos pegar a consulta acima e fazer algo assim:

query {
  Q1: order(id: "17") {
    date
    status
    products {
      name
      description
    }
    user {
      name
      email
    }
  }
  Q2: order(id: "17") {
    date
    status
    products {
      name
      description
    }
    user {
      name
      email
    }
  }
}

Desta vez, solicitámos os mesmos dados que a consulta anterior, exceto que os solicitámos duas vezes. Naturalmente, a resposta teria o dobro do tamanho da solicitação de consulta única. No entanto, e se repetíssemos a consulta 100 vezes num único pedido?

query {
  Q00: order(id: "17") {    …  }  Q01: order(id: "17") {    …  }  …  Q99: order(id: "17") {    …  }
}

Sem mais nem menos, criámos uma consulta que produziria uma resposta 100 vezes maior do que a nossa consulta original. Uma boa maneira de ilustrar esse ataque é com a seguinte imagem de cheeseburgers. Os pães de hambúrguer formam o único pedido; mas entre os pães, pode haver centenas de hambúrgueres!

consulta recheada

Se um utilizador malicioso abusar desta flexibilidade de consulta, o consumo excessivo de recursos pode sufocar o seu servidor.

Abusar das funcionalidades de paginação

O GraphQL também tem algumas formas padrão de lidar com a paginação. Uma abordagem comum é a paginação baseada em deslocamento, na qual o chamador fornece o número de itens a serem buscados (limite) e o item com o qual começar (deslocamento).

Por exemplo, uma consulta para devolver informações de uma pesquisa de produto pode ter o seguinte aspeto:

query {
  products(searchString: "shirt", limit: 8, offset: 0) {
    id
    name
    description
    sku
    category
    images {
      path
      alt_text
    }
    variations {
      name
      description
      cost
    }
  }
}

E se ajustássemos os parâmetros de paginação para executar esta consulta?

query {
  products(searchString: "shirt", limit: 800, offset: 0) {    …  }}

Num conjunto semelhante de exemplos que testei num sítio de comércio eletrónico, comparei as respostas que recebi:

$ du response*.json
680496  response_big.json
333649  response_small.json

Poder-se-ia pensar que o ficheiro grande teria cerca de 100 vezes o tamanho do ficheiro pequeno, uma vez que o limite foi definido para 800 em vez de 8. A pesquisa provavelmente não produziu 800 resultados no total (possivelmente apenas 16 a 20).

O abuso da paginação é outro exemplo de como alguém pode manipular os parâmetros de consulta GraphQL para adicionar carga ao seu servidor. Ao explorar esta funcionalidade, os atacantes podem forçar o seu servidor a tratar pedidos muito maiores do que o pretendido, levando potencialmente ao esgotamento de recursos e à negação de serviço (DoS).

OWASP API4:2023 Consumo de recursos sem restrições

O que temos estado a demonstrar enquadra-se no Top 10 de segurança de API da OWASP, especificamente API4:2023 Unrestricted Resource Consumption. Esta vulnerabilidade ocorre quando as API não limitam determinados tipos de interações ou pedidos, deixando o servidor vulnerável a ataques DoS e outras perturbações operacionais.

Quando uma API permite uma consulta excessiva ou paginação sem limites, pode levar a um consumo de recursos em espiral. Isto, por sua vez, pode causar uma degradação do desempenho ou mesmo uma falha completa do servidor. Sem limites adequados, esses ataques podem interromper o serviço. Poderá incorrer em custos operacionais elevados, ver os clientes afastarem-se e perder negócio.

Como se proteger

Para lidar com estes riscos, é necessário regular corretamente os pedidos de API. Implemente controlos que restrinjam a quantidade de dados que podem ser solicitados. Isto inclui a definição de limites para o tamanho e o número de consultas, bem como a implementação de limitação de taxas e outras medidas de proteção.

Eis algumas sugestões práticas para se proteger:

  • Limites de tamanho de carga útil de solicitação e resposta: Ao definir limites para o tamanho dos dados que podem ser solicitados e devolvidos, pode evitar que consultas demasiado grandes sobrecarreguem o seu servidor.
  • Limites de paginação: Implementar um limite máximo para a paginação, garantindo que o chamador não tenta obter mais registos do que o razoável.
  • Firewall de aplicativo Web (WAF): Um WAF pode ajudar a detetar e bloquear atividades mal-intencionadas, frustrando possíveis ataques à sua API GraphQL. Considere usar um WAF como o Haltdos do Linode Marketplace para adicionar essa camada extra de segurança.
  • Ferramentas de segurança da API: As ferramentas que podem detetar e mitigar actividades maliciosas são essenciais. Podem ajudar a identificar padrões invulgares que podem indicar um ataque, permitindo-lhe tomar medidas antes que este afecte o seu sistema.

Ao seguir essas etapas, é possível reduzir significativamente o risco de exploração do servidor GraphQL por meio do consumo excessivo de recursos. Garantir que suas interações de API sejam reguladas adequadamente ajudará a manter a estabilidade e o desempenho do seu servidor.

Para obter mais informações sobre a criação com o GraphQL, consulte GraphQL Apollo: Uma introdução com exemplos em nossos documentos.

Comentários

Deixe uma resposta

O seu endereço de correio electrónico não será publicado. Os campos obrigatórios estão marcados com *