Como aprimorar a segurança do GraphQL com análise estática e Snyk Code
Sam Sanoop
12 de abril de 2022
0 minutos de leituraGraphQL é uma linguagem de consulta para APIs desenvolvida pelo Facebook em 2015. Desde então, seus recursos e funcionalidades exclusivos fizeram dele uma alternativa viável às APIs REST. Em termos de segurança, os servidores GraphQL podem apresentar diversos tipos de configurações incorretas que resultam em comprometimento de dados, problemas de controle de acesso e outras vulnerabilidades de alto risco.
Embora os problemas de segurança do GraphQL sejam amplamente conhecidos, há poucas informações sobre como encontrá-los fora do uso da análise dinâmica. Neste post, vamos explicar como vulnerabilidades comuns do GraphQL aparecem em uma base de código e como encontrá-las usando ferramentas de análise estática e o GraphQL Security. Como muitos frameworks GraphQL amplamente utilizados fazem parte do npm, vamos nos concentrar em exemplos do ecossistema NodeJS.
Análise de fluxo de dados contaminados em frameworks GraphQL
Injeções de SQL e vulnerabilidades de desserialização foram relatadas em diversos estudos sobre endpoints GraphQL. Um exemplo disso está no relatório da HackerOne, que mostra uma injeção de SQL por meio de um parâmetro GraphQL.
Assim como os parâmetros de uma API REST, os argumentos do GraphQL podem introduzir entradas do usuário no aplicativo e, por isso, são uma fonte de dados contaminados. As ferramentas de análise estática devem conseguir identificar e modelar esses parâmetros com precisão no aplicativo.
Nos frameworks GraphQL, os resolvers fazem a correspondência entre o esquema, a função e os argumentos antes de encaminhá-los às funções resolver. O exemplo a seguir mostra o argumento args como um objeto que contém todos os argumentos GraphQL fornecidos para o campo pela operação GraphQL.
Essas expressões args podem ser rastreadas pelo mecanismo Snyk Code, que usa análise de apontamento e análise de estado de tipos para registrar com precisão a execução do programa. A análise do SonicJS pelo Snyk Code, um sistema moderno de gerenciamento de conteúdo de código aberto baseado em NodeJS, é um exemplo útil.
O SonicJS ajuda os usuários a realizar operações de CMS por meio de seu endpoint GraphQL. Uma dessas operações é a mutação fileUpdate, que permite ao usuário atualizar seus arquivos.
Essa consulta de mutação recebe entradas fornecidas pelo usuário chamadas args.filePath e args.fileContent, que são então passadas à função writeFile do objeto fileService. A implementação da função do objeto fileService está em server/services/file.service.js e pode ser vista abaixo.
Essa função recebe os argumentos do GraphQL e usa a função fs.writeFile para atualizar o arquivo no caminho informado. No entanto, ela pode ser explorada para percorrer o diretório do aplicativo e criar um novo arquivo em qualquer lugar do sistema-alvo, como na consulta GraphQL a seguir:
Essa vulnerabilidade permite executar código no sistema ao sobrescrever um dos arquivos de serviço do SonicJS com JavaScript malicioso, carregado pelo sistema SonicJS durante a inicialização ou reinicialização. Por exemplo, a instrução a seguir usa a função child_process para instalar uma porta dos fundos no aplicativo e se conectar a um endereço IP controlado por um invasor, aproveitando o programa ncat instalado no sistema-alvo.

Veja abaixo o relatório do Snyk Code sobre essa vulnerabilidade:

Para evitar essa vulnerabilidade no futuro, o SonicJS pode exigir autenticação e autorização para a consulta e validar o caminho do arquivo fornecido, garantindo que caracteres especiais como ../ não sejam permitidos.
Introspecção do GraphQL
O sistema de introspecção do GraphQL pode ser usado para descobrir quais consultas são aceitas por um servidor GraphQL. Isso inclui tipos, campos, consultas, mutações e outras informações relacionadas a um esquema GraphQL.
Embora seja um recurso, e não um problema de segurança direto, a introspecção muitas vezes pode ser usada para encontrar funcionalidades ocultas que um invasor pode explorar.
No ecossistema NodeJS, os frameworks JavaScript costumam ativar a introspecção por padrão, o que pode não ficar claro para os desenvolvedores. Assim, ao usar o framework GraphQL sem especificar configurações, como no exemplo abaixo com express-graphql, a introspecção é ativada automaticamente.
Veja abaixo um exemplo desse relatório no Snyk Code:

Como pode haver casos legítimos em que a introspecção seja necessária em um aplicativo de produção, esse problema foi classificado como baixo risco.
Para desativar a introspecção no express-graphql, use a regra NoSchemaIntrospectionCustomRule fornecida pelo graphql-js.
Embora a introspecção em produção possa levar a problemas de segurança, ela costuma ser necessária durante o desenvolvimento. Os criadores do ApolloServer resolveram esse problema ativando ou desativando a introspecção conforme o status de produção.
Se você usa outro framework GraphQL, pode recorrer a uma biblioteca de terceiros, como o pacote graphql-disable-introspection, para validar regras no seu endpoint GraphQL.
Negação de serviço no GraphQL
Cada consulta tem uma profundidade de objetos aninhados que pode ser processada por um endpoint GraphQL. A maioria dos frameworks GraphQL não define um limite de profundidade padrão. Consultas sem limite de profundidade podem deixar o framework vulnerável a ataques de negação de serviço (DoS), como no exemplo a seguir:
No entanto, para que esse problema possa ser explorado, o servidor GraphQL precisa ter um padrão recursivo de tipos de campo com uma relação bidirecional. Veja abaixo um exemplo desse relatório no Snyk Code:

Essa vulnerabilidade de DoS foi encontrada no mevn-cli. Para corrigi-la, você pode usar o pacote graphql-depth-limit, disponível no npm, da seguinte forma:
Confira este commit do repositório mevn-cli para ver um exemplo dessa correção.
Outra maneira de evitar ataques de DoS é verificar o tamanho do corpo da solicitação no seu endpoint GraphQL. Consultas grandes podem indicar ataques de DoS; por isso, monitorar o tamanho das consultas é uma verificação simples e eficaz.
Injeção de GraphQL
Ao permitir que um invasor interfira em uma consulta do aplicativo, uma injeção de GraphQL dá a agentes mal-intencionados acesso a dados que normalmente não conseguiriam obter, incluindo dados de usuários ou quaisquer outros dados acessíveis pelo aplicativo. Em muitos casos, esses dados podem ser modificados ou excluídos, causando mudanças persistentes no conteúdo e no comportamento do aplicativo.
@octokit/core é uma biblioteca minimalista criada para usar as APIs REST e GraphQL do GitHub na criação de consultas GraphQL. Quando entradas do usuário são usadas para criar uma consulta GraphQL dinamicamente, um invasor pode conseguir modificá-la para acessar informações confidenciais. Veja abaixo um exemplo desse problema:
Veja abaixo um exemplo desse relatório no Snyk Code.

Para evitar injeções de GraphQL, não passe parâmetros inseridos pelo usuário diretamente para uma consulta GraphQL. Se a entrada direta do usuário for necessária por motivos de desempenho, valide-a usando uma lista de permissões rigorosa de caracteres permitidos — evitando caracteres especiais como ? & / < > ; - e o espaço — e, se possível, use uma rotina de escape fornecida pelo fornecedor.
Conclusão
Atualmente, o Snyk Code oferece suporte aos seguintes frameworks GraphQL por meio de diversas regras semânticas e de análise de fluxo de dados contaminados:
express-graphqlkoa-graphqlmercuriusapollo-servergraphql-js
Esperamos ampliar o suporte a vulnerabilidades GraphQL, como problemas de referência direta a objetos inseguros e de controle de acesso. Embora atualmente o GraphQL seja compatível com JavaScript, nosso objetivo é adicionar suporte a mais linguagens de programação e regras de qualidade de código para lidar com problemas como ataques por processamento em lote e complexidade de consultas.
Comece a jogar Capture the Flag
Aprenda a resolver desafios de Capture the Flag assistindo à gravação sob demanda do nosso workshop virtual introdutório.


