{ }
type
GraphQL · Security · Depth Limits · Complexity · Introspection · Magento
GraphQL Security Review:
Depth, Complexity, Introspection und Abuse Cases

GraphQL-APIs sind ohne zusätzliche Schutzmaßnahmen anfällig für überladene Queries, Introspection-Angriffe, Batching-DoS und Datenlecks durch zu offene Resolver. Dieser Security-Review zeigt konkrete Angriffsszenarien und die passenden Gegenmaßnahmen.

22 Min. Lesezeit Depth Limit · Complexity · Introspection · Batching · Rate Limiting GraphQL Armor · Magento · OWASP GraphQL

1. Die besondere Angriffsfläche von GraphQL-APIs

GraphQL-APIs haben eine deutlich andere Angriffsfläche als REST-APIs. Während REST-Endpoints fest definierte Datenmengen zurückgeben, gibt GraphQL Clients die Macht, beliebig tiefe und breite Queries zu formulieren. Ohne Schutzmaßnahmen kann ein einzelner HTTP-Request eine Query senden, die Millionen von Datensätzen traversiert, alle verfügbaren Schema-Informationen extrahiert oder denselben teuren Resolver hunderte Male innerhalb einer einzigen Request ausführt. Das sind keine theoretischen Bedrohungen – Sicherheitsforscher und Angreifer nutzen diese Eigenschaften systematisch aus.

Die OWASP-GraphQL-Cheat-Sheet-Liste nennt mehrere spezifische Angriffsklassen: Overloaded Queries (extrem tiefe oder breite Queries zur Ressourcenerschöpfung), Introspection-Angriffe (Schema-Enumeration für gezieltere Folgeangriffe), Batching-Angriffe (viele Operationen in einem Request für Brute-Force ohne Rate-Limiting-Wirkung), Field Stuffing (zu viele Felder in einem Request) und Resolver-basierte Datenlecks (Felder, die ohne Autorisierungsprüfung sensible Daten zurückgeben). Jede dieser Angriffsklassen erfordert eine eigene Schutzmaßnahme – kein einzelnes Mittel schützt gegen alle.

2. Query-Depth-Limiting: tiefe Verschachtelungen blockieren

Query-Depth-Limiting ist die einfachste und direkteste Schutzmaßnahme gegen Overloaded-Query-Angriffe. GraphQL-Queries können beliebig tief verschachtelt werden – wenn das Schema es erlaubt, Produkte auf verwandte Produkte zu verweisen und diese wieder auf ihre verwandten Produkte, entsteht eine potenziell unendliche Kette. Eine Query, die diese Kette auch nur 10 Ebenen tief traversiert, kann Millionen von Datenbankzugriffen auslösen.

Depth-Limiting zählt die maximale Verschachtelungstiefe einer Query vor der Ausführung und lehnt Queries ab, die einen definierten Schwellenwert überschreiten. Ein typischer Wert für Commerce-APIs liegt zwischen 5 und 10 Ebenen. Für Magento-GraphQL, das von Natur aus tiefe Typen hat (Produkt → Preis → Mindestpreis → Endpreis → Betrag), sind 7–8 Ebenen ein realistischer Richtwert. GraphQL Armor implementiert Depth-Limiting als Plugin für Apollo Server; für PHP-basierte GraphQL-Server wie Magento gibt es entsprechende Middleware-Implementierungen oder Webserver-Level-Regex-Filter als erste Verteidigungslinie.


# GEFÄHRLICH: Query mit extremer Tiefe (Depth = 8+)
# Erzeugt exponentiell viele Datenbankzugriffe
# Depth-Limit blockiert diese Query vor der Ausführung

query DeepAttack {
  products(search: "shoe") {         # Depth 1
    items {                           # Depth 2
      related_products {              # Depth 3
        sku
        related_products {            # Depth 4
          sku
          related_products {          # Depth 5
            sku
            related_products {        # Depth 6
              sku
              related_products {      # Depth 7
                sku
              }
            }
          }
        }
      }
    }
  }
}

# SICHER: flache Query mit normalem Informationsbedarf
# Depth = 5, innerhalb des typischen Limits von 7

query SafeProductQuery {
  products(search: "shoe") {                    # Depth 1
    items {                                     # Depth 2
      sku
      name
      price_range {                             # Depth 3
        minimum_price {                         # Depth 4
          final_price { value currency }        # Depth 5
        }
      }
    }
  }
}

3. Complexity-Limits: teure Queries korrekt bewerten

Complexity-Limits sind mächtiger als Depth-Limits, weil sie die Kosten einer Query bewerten statt nur ihre Tiefe zu messen. Eine breite, aber flache Query – viele Felder auf derselben Tiefenebene – wird von einem reinen Depth-Limit nicht blockiert, kann aber trotzdem teuer sein. Complexity-Kalkulation weist jedem Feld einen Kostenwert zu und summiert diese Kosten über die gesamte Query. Listenfelder erhalten typischerweise höhere Kosten, weil jedes Element der Liste weitere Resolver-Aufrufe auslöst. Einfache Skalar-Felder erhalten niedrige Kosten.

Die Herausforderung beim Complexity-Design liegt im Kalibrieren der Feldkosten. Zu niedrige Kosten für Listenfelder schützen nicht wirksam. Zu hohe Kosten für gängige Felder machen normale Queries unerreichbar. Ein bewährter Ansatz: einfache Skalare kosten 1, Objekte kosten 1 plus die Summe ihrer Felder, Listen kosten den Multiplikator ihrer maximalen Länge mal die Kosten eines Elements. Für Magento-Queries bedeutet das: eine Produktliste mit pageSize: 100 multipliziert die Kosten aller Produkt-Felder mit 100. Ein Limit von 1000 würde diese Query mit 100 Produkten à 5 Feldern (= 500) noch zulassen, mit 200 Produkten aber blockieren.

4. Introspection: wann deaktivieren und wie schützen

GraphQL-Introspection ist das mächtige Feature, das Tools wie GraphiQL und Altair ermöglicht: Clients können das vollständige Schema abfragen, inklusive aller Typen, Felder, Argumente und Direktiven. In Entwicklungsumgebungen ist das unverzichtbar. In Produktionsumgebungen ist es ein zweischneidiges Schwert: Introspection gibt Angreifern eine vollständige Karte der API. Mit einem einzigen __schema-Query kennt ein Angreifer alle Felder, alle Typen und alle verfügbaren Operationen – was gezielte Folgeangriffe erheblich einfacher macht.

Die empfohlene Strategie für Produktions-Introspection: vollständige Deaktivierung für öffentliche Clients, eingeschränkter Zugriff für authorisierte Entwickler-Tools über IP-Allowlisting oder API-Keys. Alternativ gibt es den Ansatz des "Schema Filtering": Introspection bleibt aktiv, aber sensitive Felder (interne IDs, Debug-Felder, Admin-Mutationen) werden aus dem Introspection-Result herausgefiltert. Für Magento bedeutet das: Introspection ist standardmäßig aktiv, kann aber über einen HTTP-Header-Check oder eine Middleware für Produktions-Traffic deaktiviert werden. GraphQL Armor bietet eine einfache Konfigurationsoption dafür.


# ANGRIFF: vollständige Schema-Enumeration via Introspection
# Gibt Angreifern eine komplette API-Karte

query IntrospectionAttack {
  __schema {
    queryType { name }
    mutationType { name }
    types {
      name
      kind
      fields {
        name
        type { name kind ofType { name kind } }
        args { name type { name kind } }
      }
    }
  }
}

# In Produktion blockieren: Introspection-Handler prüft,
# ob die Query __schema oder __type enthält und lehnt ab.

# ERLAUBT in Entwicklung/Staging:
# Introspection für autorisierte Clients mit API-Key

# ERLAUBT überall: einzelne Typ-Introspection für __typename
# (wird für Apollo Client's type policies benötigt)
query TypenameOnly {
  products(search: "test") {
    items { __typename }
  }
}

5. Batching-Angriffe und Alias-Missbrauch

GraphQL-Batching ermöglicht es, mehrere Operationen in einem HTTP-Request zu bündeln. Das ist ein legitimes Performance-Feature, wird aber für Angriffe missbraucht. Ein Batching-Angriff sendet beispielsweise 100 Login-Mutations in einem einzigen HTTP-Request, um Rate-Limiting zu umgehen, das auf HTTP-Request-Ebene gemessen wird: 1 HTTP-Request enthält 100 Login-Versuche statt 100 HTTP-Requests. Ohne Batching-Schutz ist damit klassisches Brute-Force-Rate-Limiting wirkungslos.

Eine verwandte Angriffsform ist der Alias-Missbrauch: GraphQL erlaubt Aliases – unterschiedliche Namen für dasselbe Feld in einer Query. Eine Query kann denselben teuren Resolver 50 Mal mit unterschiedlichen Aliases aufrufen und so Complexity-Limits umgehen, die nur einmal pro Feldname zählen. Schutzmaßnahmen: Batching auf maximal 5–10 Operationen pro Request begrenzen, Alias-Limiting als separaten Validator implementieren und Complexity-Kalkulation so ausführen, dass Aliases vollständig mitgezählt werden. GraphQL Armor implementiert Alias-Limiting und Batching-Limits als separate Plugins.

6. Rate Limiting und Query-Allowlisting

Rate Limiting für GraphQL-APIs muss auf Operationsebene stattfinden, nicht nur auf HTTP-Request-Ebene. Da GraphQL-Batching mehrere Operationen in einem Request bündeln kann, ist ein HTTP-Level-Rate-Limit unzureichend. Effektives GraphQL-Rate-Limiting kombiniert: HTTP-Request-Rate pro Client-IP oder API-Key, Operations-Rate pro Named Operation und Query-Complexity als kumuliertes Limit über einen Zeitraum. Ein Client kann beispielsweise 1000 Complexity-Punkte pro Minute verbrauchen – eine einzelne teure Query verbraucht diese schnell, viele günstige Queries können verteilt werden.

Persisted Queries oder Query Allowlisting sind die stärkste Schutzmaßnahme für Produktions-APIs: nur vordefinierte, approved Queries werden akzeptiert. Dynamische Query-Strings von unbekannten Clients werden vollständig abgelehnt. Das eliminiert den gesamten Query-Injection-Angriffvektor und macht Depth-Limits und Complexity-Limits für bekannte Clients überflüssig – sie bleiben aber als Schutz gegen Clients, die trotzdem ungültige Queries senden. Für Magento-Headless-Frontends mit fest definiertem Query-Set ist Persisted-Query-Allowlisting gut umsetzbar; für öffentliche APIs, die dynamische Queries erlauben müssen, bleibt Complexity-Rate-Limiting die Hauptverteidigung.


# ALIAS-MISSBRAUCH: 50 teure Resolver-Aufrufe in einer Query
# Umgeht naive Complexity-Limits, die nur einmal pro Feldname zählen

query AliasAttack {
  p1: products(search: "shoe", pageSize: 100) { total_count items { sku price_range { minimum_price { final_price { value } } } } }
  p2: products(search: "shirt", pageSize: 100) { total_count items { sku price_range { minimum_price { final_price { value } } } } }
  p3: products(search: "bag", pageSize: 100) { total_count items { sku price_range { minimum_price { final_price { value } } } } }
  # ... weitere 47 Aliases
}

# SCHUTZ: Alias-Limit von maximal 5 pro Query
# Jeder Alias zählt vollständig zur Complexity
# GraphQL Armor: maxAliases: 5

# BATCHING-ANGRIFF: 100 Login-Versuche in einem HTTP-Request
# Umgeht HTTP-Level-Rate-Limiting vollständig
# [{ "query": "mutation { generateCustomerToken(email: \"test@x.de\", password: \"pass1\") { token } }" },
#  { "query": "mutation { generateCustomerToken(email: \"test@x.de\", password: \"pass2\") { token } }" },
#  ... 98 weitere Versuche ]

# SCHUTZ: Batching auf max 5 Operationen begrenzen
# Rate-Limiting auf Operations-Ebene statt nur HTTP-Level
mutation LoginAttempt($email: String!, $password: String!) {
  generateCustomerToken(email: $email, password: $password) {
    token
  }
}

7. Magento GraphQL Security-Konfiguration

Magento 2 liefert einige eingebaute GraphQL-Sicherheitsmechanismen mit. Allerdings sind die Standardwerte nicht immer für alle Produktionsszenarien optimiert. Das wichtigste Sicherheitsmerkmal: Magento prüft bei authentifizierten Queries den Bearer-Token und gibt bei ungültigem oder abgelaufenem Token einen Autorisierungsfehler zurück. Customer-Daten wie Bestellungen, Adressen und Wunschlisten sind ohne gültigen Token nicht abrufbar.

Für zusätzliche Magento-GraphQL-Sicherheit empfehlen sich folgende Maßnahmen: Introspection per Nginx- oder Apache-Konfiguration für Produktions-Traffic deaktivieren (alle Requests, die __schema oder __type im Body enthalten, mit 403 ablehnen). Depth-Limiting auf Webserver-Ebene durch Request-Body-Analyse oder als Magento-Plugin vor dem Resolver-Stack. Rate-Limiting für die /graphql-Route per Nginx limit_req_zone als ersten Layer. Für höhere Sicherheitsanforderungen: WAF-Regeln (Cloudflare, AWS WAF) mit GraphQL-Analyse-Regeln aktivieren. Persisted Queries für das Hyvä-Frontend über Apollo-Persisted-Query-Links implementieren, um nur bekannte Query-Hashes zu erlauben.

8. Sicherheitsmaßnahmen im Vergleich

Jede GraphQL-Sicherheitsmaßnahme schützt gegen spezifische Angriffsklassen. Eine umfassende Sicherheitsstrategie kombiniert mehrere Ebenen.

Maßnahme Schützt gegen Implementierung Aufwand
Depth-Limit Tiefe Verschachtelungs-Angriffe, rekursive Queries GraphQL Armor, Validation-Rule Niedrig
Complexity-Limit Breite und teure Queries, Listenmissbrauch GraphQL Armor, Custom Validator Mittel (Kalibrierung nötig)
Introspection deaktiviert Schema-Enumeration, gezielte Folgeangriffe Nginx-Rule, GraphQL-Config Niedrig
Alias-Limit Alias-Missbrauch, Complexity-Limit-Umgehung GraphQL Armor (maxAliases) Niedrig
Batching-Limit Batching-DoS, Brute-Force via Batching Middleware, GraphQL Armor Niedrig
Persisted Queries Alle dynamischen Query-Angriffe vollständig Apollo Persisted Queries, CDN Hoch (nur bei fixen Frontends)

Die wichtigste Erkenntnis für Magento-GraphQL-Security: Kein einzelnes Mittel reicht aus. Ein Angreifer, der durch das Depth-Limit kommt, scheitert am Complexity-Limit. Wer beide überwindet, wird durch Rate-Limiting verlangsamt. Introspection-Deaktivierung erschwert das Auffinden von Targets. Persisted Queries für das Hyvä-Frontend schließen den Angriffsvektor für das Frontend vollständig – während die Admin-API weiterhin volle GraphQL-Flexibilität für Entwickler bietet.

9. Zusammenfassung

GraphQL-APIs haben eine andere Sicherheitscharakteristik als REST-APIs – die Flexibilität, die GraphQL stark macht, ist gleichzeitig die Quelle der größten Angriffsflächen. Depth-Limits blockieren tiefe Verschachtelungs-Angriffe. Complexity-Limits bewerten Queries nach ihren tatsächlichen Kosten und blockieren breite, teure Queries. Introspection sollte in Produktion deaktiviert oder auf autorisierte Clients eingeschränkt werden. Alias-Limits und Batching-Limits schließen Angriffsvektoren, die naive Schutzmaßnahmen umgehen. Persisted Queries bieten den stärksten Schutz für frontends mit festem Query-Set.

Für Magento-GraphQL-APIs empfiehlt sich eine Defense-in-Depth-Strategie: Depth- und Complexity-Limits als Basis, Introspection-Deaktivierung per Nginx für öffentlichen Traffic, Rate-Limiting auf Webserver-Ebene als erster Layer und Persisted Queries für das Hyvä-Frontend als stärkste Maßnahme. Regelmäßige Security-Reviews mit Blick auf neue OWASP-GraphQL-Empfehlungen runden die Sicherheitsstrategie ab.

GraphQL Security Review — Das Wichtigste auf einen Blick

Depth + Complexity

Depth-Limit für Verschachtelungstiefe (7–10 für Magento), Complexity-Limit für Gesamtkosten – beide zusammen blockieren die häufigsten DoS-Angriffsvektoren.

Introspection

In Produktion für öffentliche Clients deaktivieren – per Nginx-Regel oder GraphQL-Config. Entwickler-Zugriff über IP-Allowlisting oder API-Key beibehalten.

Alias- und Batching-Limits

Alias-Missbrauch und Batching-DoS sind Angriffsvektoren, die Depth- und Complexity-Limits umgehen. GraphQL Armor implementiert maxAliases und Batching-Limits als Drop-in-Plugins.

Persisted Queries

Stärkste Maßnahme für feste Frontends: nur bekannte Query-Hashes erlauben. Eliminiert dynamische Query-Angriffsvektoren vollständig für das Hyvä-Frontend.

11. FAQ: GraphQL Security Review – Depth, Complexity, Introspection, Abuse Cases

1Depth-Limit: welcher Wert für Magento?
7–10 Ebenen sind realistisch für Magento, da Typen von Natur aus tief sind. Mit 10 starten, echte Queries analysieren und ggf. senken. Depth-Limit wird vor der Execution geprüft – kein Performance-Overhead.
2Warum ist Introspection in Produktion gefährlich?
Gibt Angreifern die vollständige API-Karte. Gezielt genutzt für Folgeangriffe auf sensible Felder und Mutationen. In Produktion deaktivieren oder auf autorisierte Clients einschränken.
3Was ist ein Batching-Angriff?
100 Login-Mutations in einem HTTP-Request = 100 Brute-Force-Versuche ohne HTTP-Rate-Limiting-Wirkung. Schutz: Batching auf max. 5–10 Operationen begrenzen und Operations-Rate-Limiting implementieren.
4Was ist Alias-Missbrauch?
Denselben teuren Resolver 50 Mal per Alias aufrufen – umgeht naive Complexity-Limits. Alias-Limit (maxAliases: 5) verhindert das. GraphQL Armor implementiert es als Drop-in-Plugin.
5Persisted Queries: wann lohnenswert?
Für Frontends mit festem Query-Set (Hyvä, React). Eliminiert alle dynamischen Query-Angriffsvektoren. Für öffentliche APIs mit dynamischen Queries nicht geeignet.
6Introspection in Magento deaktivieren?
Nginx: Requests mit __schema oder __type im Body mit 403 ablehnen. Oder als GraphQL-Validator-Plugin vor der Execution. Entwickler-Zugriff per IP-Allowlisting beibehalten.
7Complexity-Limits kalibrieren?
Skalare = 1, Objekte = 1 + Feldersumme, Listen = pageSize × Elementkosten. Echte Produktions-Queries analysieren. Limit = 2× maximale legitime Query-Complexity als Ausgangspunkt.
8GraphQL Armor für Magento geeignet?
GraphQL Armor ist JavaScript-first (Apollo, Yoga). Für Magento (PHP): eigene Middleware oder Webserver-Level-Regeln für die wichtigsten Maßnahmen implementieren.
9Reicht Rate-Limiting allein?
Nein. Batching umgeht HTTP-Level-Rate-Limiting. Defense-in-Depth: Rate-Limiting + Depth-Limits + Complexity-Limits + Alias-Limits + idealerweise Persisted Queries kombinieren.
10GraphQL-API auf Sicherheitslücken testen?
Tools: graphql-cop, clairvoyance. Manuell: Introspection, tiefe Queries, Batching mit 100 Ops, 50 Aliases testen. Jeder Erfolg zeigt eine fehlende Schutzmaßnahme.