Comment fonctionne cette vérification
Scanaris envoie une requête POST avec la plus petite requête d'introspection possible, {__schema{queryType{name}}}, vers trois chemins où vit habituellement un endpoint GraphQL : /graphql, /api/graphql et /v1/graphql. Si l'un d'eux répond 200 et que le corps contient __schema ou queryType, l'introspection est activée et il ouvre un constat de sévérité moyenne avec le chemin. S'il n'y a pas de GraphQL sur ton site, aucun chemin ne répond ainsi et il n'y a pas de constat. La requête est en lecture seule, ne touche à aucune donnée et passe par les mêmes limites de temps et de taille que le reste de l'analyse.
Pourquoi c'est important
L'introspection est la fonction de GraphQL qui permet de demander à l'API son propre schéma : tous les types, tous les champs de chaque type, toutes les requêtes et mutations disponibles, avec leurs arguments. En développement, elle est indispensable : c'est ce qu'utilisent le playground, l'autocomplétion de l'éditeur et les générateurs de code. En production, ouverte à tous, c'est une carte complète de ton backend. Un attaquant voit qu'il existe une mutation deleteUser(id) ou un champ internalNotes sans avoir à deviner, et va directement tester si l'autorisation de chacun est bien faite. C'est pourquoi la sévérité est moyenne : elle n'expose aucune donnée en soi, mais elle rend trivial de trouver toute autre faille de permissions.
Comment la désactiver en production
- Apollo Server :
introspection: "production" !== 'production'à la création du serveur. Depuis Apollo 4, elle est déjà désactivée quandNODE_ENVvautproduction; si tu la vois active, vérifie que cette variable arrive bien à ton déploiement. Désactive aussi la landing page ou le playground en production. - GraphQL Yoga et Envelop : le plugin
useDisableIntrospection()de@envelop/disable-introspection, conditionné à l'environnement. - Hasura (le chemin /v1/graphql) : les paramètres de sécurité du projet proposent un contrôle de l'introspection par rôle (Cloud et Enterprise). Assure-toi aussi que le rôle public a des permissions minimales et que le secret administrateur ne voyage jamais jusqu'au navigateur.
- graphql-ruby :
disable_introspection_entry_pointsdans la classe du schéma. - Python (Graphene, Strawberry, Ariadne) : ajoute la règle
NoSchemaIntrospectionCustomRuledegraphql-coreaux règles de validation en production. - .NET (Hot Chocolate) :
.AllowIntrospection(false)ou l'option pour moduler l'introspection par requête selon un en-tête ou un rôle.
Désactiver l'introspection ne remplace pas l'autorisation : chaque requête et mutation doit vérifier qui demande. Accompagne-la de limites de profondeur et de complexité des requêtes (elles évitent les requêtes imbriquées qui font tomber le serveur) et, si ton serveur le permet, désactive aussi les suggestions de champs (« Did you mean… »), qui laissent fuir des noms même avec l'introspection fermée.
Vérifie que c'est corrigé
curl -s -X POST https://tondomaine.com/graphql -H "Content-Type: application/json" -d '{"query":"{__schema{queryType{name}}}"}'
Répète avec /api/graphql et /v1/graphql. Attendu : une erreur du type « introspection is not allowed », un 400 ou 403, ou un 404 s'il n'y a pas de GraphQL là. Si tu vois "queryType":{"name":"Query"}, elle est encore ouverte.
Questions fréquentes
Mon API est publique et documentée. Suis-je concerné ?
Si tu publies le schéma volontairement, l'introspection ouverte ne révèle rien de nouveau et tu peux marquer le constat comme accepté. La plupart des API d'applications ne sont pas dans ce cas : elles ont des mutations internes que personne ne devrait connaître.
Mon endpoint est sur un autre chemin. N'est-il pas vérifié ?
Seuls les trois chemins les plus courants sont testés. Si le tien vit ailleurs, lance le test ci-dessus avec ton vrai chemin. Les autres panneaux et endpoints de développement qui ne devraient pas répondre en production sont recherchés par endpoints exposés.
Et si l'endpoint demande une authentification ?
Alors l'introspection répond 401 et n'est pas signalée. C'est la bonne situation : un attaquant sans session n'obtient pas le schéma. Vérifie que l'en-tête CORS de l'API n'est pas ouvert à n'importe quelle origine ; c'est ce que regarde CORS permissif.