Pular para o conteúdo principal
BlogComputaçã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 uma aparência de onda 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, usuários mal-intencionados podem explorar esses recursos do GraphQL, o que pode representar riscos significativos para a estabilidade do seu servidor.

Neste blog, exploraremos como a flexibilidade do GraphQL pode se voltar contra você. Estamos nos concentrando especificamente em uma vulnerabilidade destacada pelo OWASP API Security Top 10: consumo irrestrito de recursos. Também discutiremos as etapas práticas para proteger seus sistemas contra esse tipo de abuso.

Resposta do GraphQL à busca excessiva e à busca insuficiente

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, com base no ID do pedido. Com o REST, essa solicitação GET para /orders/17 buscaria não apenas o valor em dólares, mas também o seguinte:

  • dados do pedido
  • informações de faturamento
  • informações de remessa
  • quantidades de produtos
  • imposto
  • status do pedido
  • ... e mais

Isso é buscar demais.

Com o REST, você também encontra sub-busca quando precisa reunir dados associados de vários recursos. Imagine que você queira exibir um resumo, com a data e o status de um pedido, os nomes e as descrições de todos os produtos do pedido e o nome e o e-mail do usuário que fez o pedido. Para fazer isso, você precisaria enviar várias solicitações:

  • GET /orders/17
  • GET /produtos/1662527
  • GET /produtos/9914188
  • GET /produtos/3750021
  • GET /produtos/7557109
  • GET /products/6081142
  • GET /users/3314

O GraphQL foi a resposta para essas deficiências do REST. Você pode consultar exatamente o que precisa, em todos os recursos associados. Para realizar o que foi mencionado 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, esse nível de flexibilidade também significa que um usuário mal-intencionado pode deliberadamente buscar dados em excesso.

Abusar da flexibilidade da consulta

A sintaxe de consulta do GraphQL permite que você execute várias consultas na mesma solicitação. Poderíamos usar 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, solicitamos os mesmos dados da consulta anterior, só que os solicitamos 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 em uma única solicitação?

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

Dessa forma, criamos uma consulta que produziria uma resposta 100 vezes maior do que a consulta original. Uma boa maneira de ilustrar esse ataque é com a seguinte imagem de cheeseburgers. Os pães de hambúrguer formam a única solicitação, mas, entre os pães, você pode ter centenas de hambúrgueres!

consulta recheada

Se um usuário mal-intencionado abusar dessa flexibilidade de consulta, o consumo excessivo de recursos poderá sufocar o seu servidor.

Uso indevido de recursos 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 retornar informações de uma pesquisa de produto pode ser assim:

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 essa consulta em vez disso?

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

Em um conjunto semelhante de exemplos que testei em um site de comércio eletrônico, comparei as respostas que recebi:

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

Você poderia pensar que o arquivo grande teria aproximadamente 100 vezes o tamanho do arquivo pequeno, já que o limite foi definido como 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 do GraphQL para adicionar carga ao seu servidor. Ao explorar esse recurso, os invasores podem forçar seu servidor a lidar com solicitações muito maiores do que o pretendido, o que pode levar ao esgotamento de recursos e à negação de serviço (DoS).

OWASP API4:2023 Consumo irrestrito de recursos

O que estamos demonstrando se enquadra no Top 10 de segurança de API da OWASP, especificamente na API4:2023 Consumo irrestrito de recursos. Essa vulnerabilidade ocorre quando as APIs não limitam determinados tipos de interações ou solicitações, deixando o servidor vulnerável a ataques de DoS e outras interrupções operacionais.

Quando uma API permite consultas excessivas ou paginação sem limites, isso pode levar a um consumo de recursos em espiral. Isso, por sua vez, pode causar degradação do desempenho ou até mesmo falha total do servidor. Sem a implementação de limites adequados, esses ataques podem interromper o serviço. Você pode incorrer em altos custos operacionais, ver os clientes se afastarem e perder negócios.

Como se proteger

Para lidar com esses riscos, você precisa regular adequadamente as solicitações de API. Implemente controles que restrinjam a quantidade de dados que podem ser solicitados. Isso inclui a definição de limites para o tamanho e o número de consultas, bem como a implementação de limitação de taxa e outras medidas de proteção.

Aqui estão algumas sugestões práticas para se proteger:

  • Limites de tamanho da carga útil da solicitação e da resposta: Ao definir limites para o tamanho dos dados que podem ser solicitados e retornados, você pode evitar que consultas muito grandes sobrecarreguem o servidor.
  • Limites de paginação: Implemente um limite máximo para paginação, garantindo que um chamador não tente buscar mais registros do que o razoável.
  • Firewall de aplicativos da Web (WAF): Um WAF pode ajudar a detectar e bloquear atividades mal-intencionadas, impedindo 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 de API: As ferramentas que podem detectar e atenuar atividades mal-intencionadas são essenciais. Elas podem ajudar a identificar padrões incomuns que podem indicar um ataque, permitindo que você tome medidas antes que ele afete seu sistema.

Ao adotar essas etapas, você pode reduzir significativamente o risco de exploração do seu servidor GraphQL por meio do consumo excessivo de recursos. Garantir que as interações da 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 GraphQL, consulte GraphQL Apollo: Uma introdução com exemplos em nossa documentação.

Comentários

Deixe uma resposta

Seu endereço de e-mail não será publicado. Os campos obrigatórios estão marcados com *