GraphQL Introspection in Produktion deaktivieren: Sicherheitsrisiken verstehen
AI generated
{ }
type
GraphQL · Introspection · Sicherheit · Produktion
GraphQL Introspection in Produktion deaktivieren
ein offenes Schema ist eine offene Landkarte

Introspection ist eine der elegantesten Eigenschaften von GraphQL, denn sie erlaubt es, das komplette Schema per Query abzufragen. Genau das macht sie in Produktion riskant: Jeder, der die API kennt, kann interne Feldnamen, Mutationen mit Zugriff auf sensible Daten und sogar Deprecation-Kommentare auslesen, ohne einen einzigen Endpunkt zu erraten. Wer Introspection nicht bewusst absichert, liefert Angreifern die vollständige Landkarte der eigenen API.

16 Min. Lesezeit Schema-Introspection · __schema · Middleware Apollo Server · GraphQL Yoga · Magento GraphQL

1. Was Introspection technisch bedeutet

GraphQL Introspection ist ein fester Bestandteil der GraphQL-Spezifikation und erlaubt es, das Schema über spezielle Meta-Felder wie __schema und __type per Query abzufragen. Jeder Typ, jedes Feld, jedes Argument und jede Beschreibung, die im Schema hinterlegt ist, lässt sich damit programmatisch auslesen, ohne die Dokumentation oder den Quellcode zu kennen. Genau diese Eigenschaft macht Tools wie GraphiQL, Apollo Studio und die Autovervollständigung in IDEs überhaupt erst möglich.

Der Haken: GraphQL Introspection ist standardmäßig bei den meisten Server-Implementierungen aktiviert, auch in Produktion, und unterscheidet nicht zwischen einem internen Entwicklerteam und einem anonymen Angreifer im Internet. Wer einen GraphQL-Endpunkt erreichen kann, kann in aller Regel auch dessen komplettes Schema abfragen, sofern niemand diese Funktion explizit eingeschränkt hat. Dieser Artikel erklärt, welche Risiken offene Introspection in Produktion mit sich bringt und wie man sie sauber deaktiviert.


# A minimal introspection query that reveals the entire schema structure
query IntrospectionQuery {
  __schema {
    types {
      name
      description
      fields {
        name
        description
        args { name type { name } }
        deprecationReason
      }
    }
    mutationType {
      fields { name description }
    }
  }
}

2. Welche Informationen Introspection tatsächlich preisgibt

Eine vollständige GraphQL Introspection-Antwort enthält weit mehr als nur Feldnamen. Sie umfasst alle verfügbaren Queries, Mutations und Subscriptions samt Argumenten und Rückgabetypen, alle Enum-Werte, alle Interface- und Union-Beziehungen sowie sämtliche Beschreibungstexte, die Entwickler als Dokumentation im Schema hinterlegt haben. Besonders brisant sind Deprecation-Kommentare: Ein Feld wie @deprecated(reason: "Use adminOverridePrice instead, internal only") verrät einem Angreifer nicht nur, dass ein altes Feld existiert, sondern liefert gleich den Namen des Nachfolgers samt Hinweis auf dessen sensiblen Charakter.

Auch Mutationen, die eigentlich nur für interne Admin-Oberflächen gedacht sind, tauchen in der GraphQL Introspection-Antwort auf, selbst wenn sie im Frontend nirgends verlinkt sind. Security by obscurity, also sich darauf zu verlassen, dass niemand einen bestimmten Mutation-Namen errät, funktioniert bei GraphQL grundsätzlich nicht, weil Introspection genau diese Namen auf Anfrage preisgibt. Ohne Feld-Level-Autorisierung ist ein aufgedecktes internes Feld direkt angreifbar, sobald sein Name bekannt ist.

3. Wie Angreifer Introspection-Daten konkret nutzen

In der Praxis ist GraphQL Introspection meist der erste Schritt in der Reconnaissance-Phase eines Angriffs. Automatisierte Tools wie InQL oder GraphQL Voyager laden das komplette Schema herunter und visualisieren es als durchsuchbare Baumstruktur, inklusive aller Typen und Beziehungen. Damit lässt sich in Minuten eine Angriffsfläche kartieren, für die man ohne Introspection tage- oder wochenlang Endpunkte hätte erraten müssen.

Konkret nutzen Angreifer die gewonnenen Informationen für gezielte Batch-Angriffe auf teure Felder, siehe Query-Complexity-Angriffe, für das Auffinden von Mutations ohne ausreichende Autorisierung sowie für Enumeration-Angriffe auf Felder mit vorhersagbaren IDs. Auch das Kartieren von internen Enum-Werten, etwa interne Status-Codes eines Bestellprozesses, kann Geschäftslogik verraten, die eigentlich nicht öffentlich sein sollte. GraphQL Introspection selbst ist also kein direkter Exploit, sondern die Grundlage, auf der gezieltere Angriffe aufbauen.

4. Warum Deaktivieren nicht die einzige Maßnahme sein darf

Ein wichtiger Punkt vorweg: Das Deaktivieren von GraphQL Introspection ist kein Ersatz für saubere Autorisierung. Ein Angreifer, der das Schema nicht per Introspection abfragen kann, kann trotzdem Felder erraten, aus JavaScript-Bundles im Frontend extrahieren oder über Fehlermeldungen erschließen. Introspection zu deaktivieren reduziert die Angriffsfläche, beseitigt sie aber nicht, und ersetzt keine Feld-Level-Autorisierung, die tatsächlich prüft, ob ein Nutzer berechtigt ist, ein Feld zu lesen oder eine Mutation auszuführen.

Die richtige Reihenfolge ist deshalb: Zuerst saubere Autorisierung auf Resolver-Ebene sicherstellen, danach GraphQL Introspection als zusätzliche Verteidigungsschicht in Produktion deaktivieren. Wer sich ausschließlich auf das Abschalten von Introspection verlässt, ohne die dahinterliegenden Berechtigungen zu prüfen, hat lediglich die Auffindbarkeit reduziert, nicht die eigentliche Schwachstelle behoben.

5. Introspection serverseitig deaktivieren

Apollo Server bietet eine eingebaute Option, um GraphQL Introspection vollständig abzuschalten, meist gekoppelt an eine Umgebungsvariable. GraphQL Yoga und andere Server bieten vergleichbare Konfigurationsoptionen oder erlauben das Entfernen der Introspection-Felder über ein Plugin, das die Meta-Felder __schema und __type aus jeder eingehenden Query vor der Validierung herausfiltert. Wichtig ist, die Deaktivierung nicht nur im Frontend-Client zu verstecken, sondern tatsächlich serverseitig zu erzwingen, da ein Angreifer die API direkt anspricht und keinen Client benutzt.

Für Magento-Umgebungen mit dem nativen GraphQL-Modul lässt sich Introspection über eine eigene Middleware oder einen Plugin auf den GraphQL-Controller einschränken, da Magento selbst keine native Konfigurationsoption zum Abschalten von Introspection mitbringt. Eine robuste Lösung prüft eingehende Queries auf __schema- oder __type-Vorkommen und lehnt diese Anfragen ab, bevor sie den regulären Query-Executor erreichen.


// server.js — disabling introspection in production with Apollo Server
import { ApolloServer } from '@apollo/server';
import { ApolloServerPluginLandingPageDisabled } from '@apollo/server/plugin/disabled';

const isProduction = process.env.NODE_ENV === 'production';

const server = new ApolloServer({
  schema,
  introspection: !isProduction,
  plugins: isProduction ? [ApolloServerPluginLandingPageDisabled()] : [],
});

// yoga.js — GraphQL Yoga equivalent using a plugin
import { createYoga } from 'graphql-yoga';
import { useDisableIntrospection } from '@graphql-yoga/plugin-disable-introspection';

const yoga = createYoga({
  schema,
  plugins: isProduction ? [useDisableIntrospection()] : [],
});

6. Umgebungsabhängige Konfiguration: Dev vs. Produktion

Eine pauschale Deaktivierung von GraphQL Introspection über alle Umgebungen hinweg ist selten sinnvoll, weil Entwicklerteams in Staging und lokaler Entwicklung auf Introspection angewiesen sind, etwa für automatische Typgenerierung im Frontend oder für die IDE-Autovervollständigung. Die gängige Praxis ist eine strikte Trennung nach NODE_ENV oder einer vergleichbaren Umgebungsvariable: Introspection bleibt in Development und Staging aktiv, wird aber in Produktion konsequent abgeschaltet.

Ein häufiger Fehler ist, diese Umgebungsvariable falsch zu setzen oder beim Deployment zu vergessen, sodass Produktionsserver versehentlich mit aktivierter GraphQL Introspection laufen. Ein automatisierter Check in der CI-Pipeline, der eine Introspection-Query gegen die Produktions-URL sendet und bei erfolgreicher Antwort den Deployment-Prozess stoppt, verhindert genau diesen Konfigurationsfehler zuverlässig, statt sich auf manuelle Prüfung zu verlassen.


# CI check — fail the pipeline if introspection is reachable in production
#!/usr/bin/env bash
set -euo pipefail

RESPONSE=$(curl -s -X POST https://api.mironsoft.de/graphql \
  -H "Content-Type: application/json" \
  -d '{"query": "{ __schema { types { name } } }"}')

if echo "$RESPONSE" | grep -q '"__schema"'; then
  echo "[FAIL] Introspection is enabled in production!" >&2
  exit 1
fi

echo "[OK] Introspection is disabled in production"

7. Interne Tools trotzdem mit Zugriff versorgen

Ein reines Abschalten von GraphQL Introspection kann interne Werkzeuge wie ein API-Monitoring-Dashboard oder eine Schema-Diff-Prüfung in der CI-Pipeline stören, die selbst regelmäßig Introspection-Queries ausführen. Die praktikable Lösung ist ein separater, authentifizierter Introspection-Endpunkt oder eine IP-Whitelist beziehungsweise ein VPN-geschützter Zugang, über den ausschließlich internes Tooling Introspection-Zugriff erhält, während der öffentliche Endpunkt vollständig geschlossen bleibt.

Eine noch sauberere Alternative ist eine separate Schema-Registry wie Apollo GraphOS oder Hive, die das Schema unabhängig vom laufenden Produktionsserver speichert und internen Tools über eine eigene, authentifizierte API zur Verfügung stellt. So muss die produktive GraphQL Introspection gar nicht erst für Tooling-Zwecke offen bleiben, weil die Schema-Information aus einer separaten, kontrollierten Quelle kommt, statt live vom Produktionsserver abgefragt zu werden.


// server.js — allowing introspection only for an internal, authenticated route
const isInternalTooling = (req) =>
  req.headers['x-internal-token'] === process.env.INTERNAL_TOOLING_TOKEN;

const server = new ApolloServer({
  schema,
  introspection: true, // validated per-request below, not globally
});

app.post('/graphql', async (req, res, next) => {
  const hasIntrospectionField = JSON.stringify(req.body).includes('__schema');
  if (hasIntrospectionField && !isInternalTooling(req)) {
    return res.status(403).json({
      errors: [{ message: 'Introspection is disabled for public clients' }],
    });
  }
  next();
});

8. Alternativen: Persisted Queries und Schema-Registry

Persisted Queries reduzieren das Risiko, das von deaktivierter GraphQL Introspection übrig bleibt, noch weiter: Statt beliebige Query-Strings zu akzeptieren, erlaubt der Server nur eine vordefinierte Liste von Query-Hashes, die beim Build des Frontends registriert wurden. Ein Angreifer kann dann selbst mit erratenen Feldnamen keine neue, beliebige Query gegen die API ausführen, da nur bereits bekannte Query-Signaturen akzeptiert werden.


{
  "extensions": {
    "persistedQuery": {
      "version": 1,
      "sha256Hash": "b1946ac92492d2347c6235b4d2611184"
    }
  },
  "variables": { "productId": "xyz789" }
}

Wird der Hash nicht in der server-seitigen Registry gefunden, lehnt der Server die Anfrage ab, unabhängig davon, ob die zugrunde liegende Query gültiges GraphQL-Syntax wäre.

Eine Schema-Registry ergänzt diesen Ansatz organisatorisch: Änderungen am Schema werden zentral versioniert, Breaking Changes werden vor dem Deployment erkannt, und Teams behalten trotz deaktivierter GraphQL Introspection in Produktion vollen Einblick in die Schema-Historie über ein separates, autorisiertes System. Für Teams mit mehreren Konsumenten der API, etwa mehreren Frontend-Anwendungen, ist die Kombination aus Persisted Queries und Schema-Registry die robusteste Lösung.

9. Introspection-Strategien im Vergleich

Die folgende Übersicht ordnet die gängigen Ansätze zum Umgang mit GraphQL Introspection nach Schutzwirkung und Komplexität ein.

Strategie Schutzwirkung Beeinträchtigt interne Tools Aufwand
Introspection überall aktiv Keine Nein Keiner
Pauschal deaktiviert Mittel Ja Niedrig
Nur in Produktion deaktiviert Hoch Nein Niedrig
Deaktiviert + Persisted Queries + Registry Sehr hoch Nein Hoch

Für die meisten Teams ist die umgebungsabhängige Deaktivierung von GraphQL Introspection in Produktion der pragmatische Standard, ergänzt um Persisted Queries, sobald mehrere Frontend-Clients dieselbe API konsumieren und ein zusätzliches Sicherheitsniveau gerechtfertigt ist.

Mironsoft

GraphQL-Sicherheit, API-Härtung und Magento-Integrationen

Läuft eure GraphQL-API mit offener Introspection in Produktion?

Wir prüfen euren Endpunkt, deaktivieren Introspection sauber nach Umgebung und richten Persisted Queries sowie Feld-Level-Autorisierung ein, wo es wirklich zählt.

Security-Check

Prüfung, ob Introspection und andere Metadaten öffentlich erreichbar sind

Konfiguration

Saubere Deaktivierung nach Umgebung, ohne interne Tools zu blockieren

CI-Absicherung

Automatisierte Checks, die Fehlkonfigurationen vor dem Deployment stoppen

10. Zusammenfassung

GraphQL Introspection ist eine mächtige Entwicklerfunktion, die in Produktion aber ungewollt das komplette Schema offenlegt, inklusive interner Felder, Mutationen und Deprecation-Hinweisen. Angreifer nutzen diese Information als Reconnaissance-Basis für gezieltere Angriffe wie Query-Complexity-Attacken oder das Auffinden unzureichend geschützter Mutations. Introspection zu deaktivieren ersetzt keine saubere Autorisierung, reduziert aber die Angriffsfläche erheblich und sollte deshalb konsequent für Produktionsumgebungen umgesetzt werden.

Die pragmatischste Umsetzung ist eine umgebungsabhängige Konfiguration: Introspection bleibt in Development und Staging aktiv, wird aber über eine Umgebungsvariable in Produktion abgeschaltet, mit einem CI-Check, der Fehlkonfigurationen vor dem Deployment abfängt. Interne Tools bekommen bei Bedarf einen separaten, authentifizierten Zugang oder eine dedizierte Schema-Registry, sodass GraphQL Introspection in Produktion vollständig geschlossen bleiben kann, ohne die eigene Entwicklungsarbeit zu behindern.

GraphQL Introspection in Produktion deaktivieren — Das Wichtigste auf einen Blick

Was Introspection preisgibt

Komplettes Schema inklusive interner Felder, Mutations, Enum-Werten und Deprecation-Kommentaren, ohne dass ein Endpunkt erraten werden muss.

Kein Ersatz für Autorisierung

Deaktivierung reduziert die Angriffsfläche, ersetzt aber keine Feld-Level-Autorisierung auf Resolver-Ebene.

Umgebungsabhängig konfigurieren

Aktiv in Dev und Staging, deaktiviert in Produktion, per Umgebungsvariable und mit CI-Check abgesichert.

Ergänzende Maßnahmen

Persisted Queries und eine Schema-Registry schließen die Lücke weiter, sobald mehrere Clients dieselbe API nutzen.

11. FAQ: GraphQL Introspection in Produktion deaktivieren

1Was ist GraphQL Introspection?
Eine feste Eigenschaft der Spezifikation, die das komplette Schema per Query über __schema und __type auslesbar macht.
2Warum ist das ein Risiko?
Sie liefert Angreifern eine öffentliche Landkarte aller internen Felder und Mutationen ohne Raten nötig.
3Reicht Deaktivieren allein?
Nein, ersetzt keine Feld-Level-Autorisierung, reduziert nur die Auffindbarkeit.
4Wie in Apollo Server deaktivieren?
Über die eingebaute introspection-Option, meist an NODE_ENV gekoppelt.
5Wie bei Magento GraphQL?
Über eine eigene Middleware oder Plugin, das __schema/__type-Vorkommen vor Ausführung ablehnt.
6Wie behalten interne Tools Zugriff?
Über separaten authentifizierten Endpunkt, IP-Whitelist oder eine dedizierte Schema-Registry.
7Was sind Persisted Queries?
Nur vordefinierte Query-Hashes werden akzeptiert, beliebige neue Queries sind blockiert.
8Wie automatisiert prüfen?
CI-Check sendet Introspection-Query gegen Produktions-URL und bricht bei Erfolg die Pipeline ab.
9Verrät sie Deprecation-Kommentare?
Ja, inklusive Reason-Text, der sensible Nachfolgefelder direkt benennen kann.
10Auch in Staging deaktivieren?
Meist nicht nötig, Staging besser über Basic Auth oder VPN absichern statt Introspection zu blockieren.