Wie diese Prüfung funktioniert
Scanaris schickt eine POST-Anfrage mit der kleinstmöglichen Introspektionsabfrage, {__schema{queryType{name}}}, an drei Pfade, unter denen ein GraphQL-Endpunkt üblicherweise liegt: /graphql, /api/graphql und /v1/graphql. Antwortet einer davon mit 200 und enthält der Body __schema oder queryType, ist die Introspektion aktiv und er öffnet einen Befund mit mittlerem Schweregrad und dem Pfad. Gibt es auf deiner Seite kein GraphQL, antwortet kein Pfad so und es gibt keinen Befund. Die Abfrage ist nur lesend, berührt keine Daten und unterliegt denselben Zeit- und Größenlimits wie der Rest des Scans.
Warum das wichtig ist
Introspektion ist die GraphQL-Funktion, mit der man die API nach ihrem eigenen Schema fragen kann: jeden Typ, jedes Feld jedes Typs, jede verfügbare Query und Mutation samt Argumenten. In der Entwicklung ist sie unverzichtbar: Playground, Editor-Autovervollständigung und Code-Generatoren stützen sich darauf. In Produktion, für jeden offen, ist sie eine vollständige Karte deines Backends. Ein Angreifer sieht, dass es eine Mutation deleteUser(id) oder ein Feld internalNotes gibt, ohne raten zu müssen, und testet direkt, ob die Autorisierung bei jedem davon sauber ist. Deshalb mittlerer Schweregrad: Sie gibt selbst keine Daten preis, macht aber jeden anderen Berechtigungsfehler trivial auffindbar.
So schaltest du sie in Produktion ab
- Apollo Server:
introspection: "production" !== 'production'beim Erstellen des Servers. Seit Apollo 4 ist sie bereits aus, wennNODE_ENVaufproductionsteht; siehst du sie aktiv, prüf, ob die Variable wirklich in deinem Deployment ankommt. Schalte in Produktion auch Landing Page oder Playground ab. - GraphQL Yoga und Envelop: das Plugin
useDisableIntrospection()aus@envelop/disable-introspection, abhängig von der Umgebung. - Hasura (der Pfad /v1/graphql): In den Sicherheitseinstellungen des Projekts gibt es eine Introspektionskontrolle pro Rolle (Cloud und Enterprise). Stell außerdem sicher, dass die öffentliche Rolle minimale Rechte hat und das Admin-Secret nie in den Browser gelangt.
- graphql-ruby:
disable_introspection_entry_pointsin der Schema-Klasse. - Python (Graphene, Strawberry, Ariadne): füge die Regel
NoSchemaIntrospectionCustomRuleausgraphql-corein Produktion zu den Validierungsregeln hinzu. - .NET (Hot Chocolate):
.AllowIntrospection(false)oder die Option, die Introspektion pro Anfrage anhand eines Headers oder einer Rolle zu steuern.
Introspektion abzuschalten ersetzt keine Autorisierung: Jede Query und Mutation muss prüfen, wer fragt. Ergänze sie um Limits für Abfragetiefe und -komplexität (sie verhindern verschachtelte Abfragen, die den Server lahmlegen) und schalte, wenn dein Server es anbietet, auch die Feldvorschläge („Did you mean…") ab, die Namen verraten, selbst wenn die Introspektion geschlossen ist.
Prüf, ob es behoben ist
curl -s -X POST https://deinedomain.de/graphql -H "Content-Type: application/json" -d '{"query":"{__schema{queryType{name}}}"}'
Wiederhole das mit /api/graphql und /v1/graphql. Erwartet: ein Fehler wie „introspection is not allowed", ein 400 oder 403, oder ein 404, wenn dort kein GraphQL liegt. Siehst du "queryType":{"name":"Query"}, ist sie noch offen.
Häufige Fragen
Meine API ist öffentlich und dokumentiert. Betrifft mich das?
Wenn du das Schema absichtlich veröffentlichst, verrät die offene Introspektion nichts Neues und du kannst den Befund als akzeptiert markieren. Die meisten Anwendungs-APIs sind nicht in dieser Lage: Sie haben interne Mutationen, die niemand kennen sollte.
Mein Endpunkt liegt auf einem anderen Pfad. Wird er nicht geprüft?
Es werden nur die drei häufigsten Pfade getestet. Liegt deiner woanders, führ den Test oben mit deinem echten Pfad aus. Andere Panels und Entwicklungsendpunkte, die in Produktion nicht antworten sollten, sucht exponierte Endpunkte.
Und wenn der Endpunkt Authentifizierung verlangt?
Dann antwortet die Introspektion mit 401 und wird nicht gemeldet. Das ist die richtige Situation: Ein Angreifer ohne Sitzung bekommt kein Schema. Prüf, dass der CORS-Header der API nicht für jede Herkunft offen ist; das schaut sich permissives CORS an.