Améliorer la sécurité de GraphQL grâce à l’analyse statique et à Snyk Code
Sam Sanoop
12 avril 2022
0 minutes de lectureGraphQL est un langage de requête pour API développé par Facebook en 2015. Depuis, ses fonctionnalités et capacités uniques en ont fait une alternative viable aux API REST. Côté sécurité, les serveurs GraphQL peuvent présenter plusieurs types d’erreurs de configuration, susceptibles d’entraîner une compromission des données, des problèmes de contrôle d’accès et d’autres vulnérabilités à haut risque.
Les problèmes de sécurité liés à GraphQL sont bien connus, mais les informations sur la manière de les détecter sont rares en dehors de l’analyse dynamique. Dans cet article, nous verrons comment les vulnérabilités GraphQL courantes se manifestent dans une base de code et comment les détecter à l’aide des outils d’analyse statique et de GraphQL Security. Comme de nombreux frameworks GraphQL utilisés sont disponibles sur npm, nous nous concentrerons sur des exemples de l’écosystème NodeJS.
Analyse de contamination dans les frameworks GraphQL
De nombreuses études portant sur les endpoints GraphQL ont signalé des vulnérabilités d’injection SQL et de désérialisation. On en trouve un exemple dans le rapport de HackerOne, où une injection SQL est possible via un paramètre GraphQL.
Comme les paramètres d’une API REST, les arguments GraphQL peuvent être contaminés par des données saisies par l’utilisateur dans une application. Les outils d’analyse statique doivent pouvoir identifier et modéliser ces paramètres avec précision dans une application.
Dans les frameworks GraphQL, les résolveurs font le lien entre le schéma, la fonction et les arguments avant de transmettre ces derniers aux fonctions de résolution. L’exemple suivant montre l’argument args sous la forme d’un objet contenant tous les arguments GraphQL fournis pour le champ par l’opération GraphQL.
Le moteur Snyk Code peut suivre ces expressions args et s’appuie sur l’analyse des points d’accès et l’analyse de l’état des types pour enregistrer avec précision l’exécution du programme. L’analyse de SonicJS par Snyk Code, un système moderne de gestion de contenu open source basé sur NodeJs, en est un bon exemple.
SonicJS permet aux utilisateurs d’effectuer des opérations de gestion de contenu via son endpoint GraphQL. L’une de ces opérations est la mutation fileUpdate, qui permet à un utilisateur de mettre à jour ses fichiers.
Cette requête de mutation prend en entrée les données fournies par l’utilisateur, args.filePath et args.fileContent, puis les transmet à la fonction writeFile de l’objet fileService. L’implémentation de la fonction de l’objet fileService se trouve dans server/services/file.service.js et est présentée ci-dessous.
Cette fonction utilise les deux arguments GraphQL et appelle la fonction fs.writeFile pour mettre à jour le fichier à l’emplacement indiqué. Cependant, elle peut être exploitée pour parcourir le répertoire de l’application et créer un nouveau fichier n’importe où sur le système cible, comme dans la requête GraphQL suivante :
Cette vulnérabilité permet d’exécuter du code sur le système en écrasant l’un des fichiers de service de SonicJS avec du JavaScript malveillant, chargé par SonicJS au démarrage ou au redémarrage. Par exemple, l’instruction suivante utilise la fonction child_process pour installer une porte dérobée dans l’application et se connecter à une adresse IP contrôlée par un attaquant, en s’appuyant sur le programme ncat installé sur le système cible.

Vous trouverez ci-dessous le rapport de Snyk Code sur cette vulnérabilité :

SonicJS peut prévenir cette vulnérabilité à l’avenir en exigeant une authentification et une autorisation pour la requête, et en validant le chemin de fichier fourni afin de refuser les caractères spéciaux tels que ../.
Introspection GraphQL
Le système d’introspection de GraphQL permet de découvrir les requêtes prises en charge par un serveur GraphQL. Il fournit notamment des informations sur les types, les champs, les requêtes, les mutations et d’autres éléments liés au schéma GraphQL.
Bien qu’il s’agisse d’une fonctionnalité et non d’un problème de sécurité direct, l’introspection peut souvent servir à repérer des fonctionnalités cachées qu’un attaquant pourrait exploiter.
Dans l’écosystème NodeJS, les frameworks JavaScript activent souvent l’introspection par défaut, sans que cela soit forcément évident pour les développeurs. Ainsi, si vous utilisez un framework GraphQL sans spécifier de paramètres, comme express-graphql ci-dessous, l’introspection est activée automatiquement.
Vous trouverez ci-dessous un exemple de ce rapport dans Snyk Code :

Comme il peut être légitime d’avoir besoin de l’introspection dans une application en production, ce problème a été classé comme présentant un risque faible.
Pour désactiver l’introspection dans express-graphql, utilisez NoSchemaIntrospectionCustomRule, fourni par graphql-js.
L’introspection en production peut entraîner des problèmes de sécurité, mais elle est souvent nécessaire en développement. Les créateurs d’ApolloServer ont résolu ce problème en activant ou désactivant l’introspection selon que l’application est en production.
Si vous utilisez un autre framework GraphQL, vous pouvez vous servir d’une bibliothèque tierce telle que le package graphql-disable-introspection pour valider les règles de votre endpoint GraphQL.
Déni de service GraphQL
Chaque requête comporte une profondeur d’objets imbriqués que peut traiter un endpoint GraphQL. La plupart des frameworks GraphQL ne définissent aucune limite de profondeur par défaut. Des requêtes à profondeur illimitée peuvent exposer le framework à des attaques par déni de service (DoS), comme dans l’exemple suivant :
Toutefois, pour que ce problème puisse être exploité, le serveur GraphQL doit présenter un schéma récursif de types de champs comportant une relation bidirectionnelle. Vous trouverez ci-dessous un exemple de ce rapport dans Snyk Code :

Cette vulnérabilité DoS a été découverte dans mevn-cli. Pour la corriger, vous pouvez utiliser le package graphql-depth-limit disponible sur npm, comme suit :
Consultez ce commit du dépôt mevn-cli pour voir un exemple de cette correction.
Une autre façon de prévenir les attaques DoS consiste à vérifier la taille du corps de la requête sur votre endpoint GraphQL. Les requêtes volumineuses peuvent signaler une attaque DoS : surveiller leur taille est donc une vérification simple et efficace.
Injection GraphQL
En permettant à un attaquant d’interférer avec une requête de l’application, une injection GraphQL peut donner à des acteurs malveillants accès à des données qu’ils ne devraient normalement pas pouvoir récupérer, notamment des données utilisateur ou toute autre donnée accessible à l’application. Dans bien des cas, ces données peuvent être modifiées ou supprimées, entraînant des changements persistants dans le contenu et le comportement de l’application.
@octokit/core est une bibliothèque minimaliste conçue pour utiliser les API REST et GraphQL de GitHub afin de créer des requêtes GraphQL. Lorsque des données saisies par l’utilisateur servent à créer dynamiquement une requête GraphQL, un attaquant peut être en mesure de la modifier pour accéder à des informations confidentielles. Vous trouverez ci-dessous un exemple de ce problème :
Vous trouverez ci-dessous un exemple de ce rapport dans Snyk Code.

Pour prévenir les injections GraphQL, évitez de transmettre directement les paramètres saisis par l’utilisateur à une requête GraphQL. Si la saisie directe est nécessaire pour des raisons de performances, validez-la à l’aide d’une liste d’autorisation très stricte des caractères permis — en excluant les caractères spéciaux tels que ? & / < > ; - et l’espace — et utilisez si possible une fonction d’échappement fournie par le fournisseur.
Conclusion
Snyk Code prend actuellement en charge les frameworks GraphQL suivants grâce à diverses règles d’analyse de contamination et règles sémantiques :
express-graphqlkoa-graphqlmercuriusapollo-servergraphql-js
Nous espérons étendre la prise en charge à d’autres vulnérabilités GraphQL, comme les problèmes de référence directe d’objet non sécurisée et de contrôle d’accès. GraphQL est actuellement pris en charge pour JavaScript, et nous souhaitons ajouter d’autres langages et règles de qualité du code afin de traiter des problèmes tels que les attaques par lots et la complexité des requêtes.
Lancez-vous dans les compétitions Capture The Flag
Apprenez à résoudre des défis Capture The Flag en regardant à la demande notre atelier virtuel d’initiation.


