Infrastruktur-PentestFabian Gold7 min Lesezeit

Schwachstellen in GraphQL - Überblick und Fallbeispiele

Diese Auskunftsfähigkeit von GraphQL ist sowohl Stärke als auch Schwäche zugleich und sollte entsprechend getestet werden.

Was ist GraphQL?

GraphQL ist eine Abfragesprache für APIs. Wie der Name bereits andeutet, eignet sie sich besonders gut für die Abfrage von Daten, die sich als Graph darstellen lassen. Im Vergleich zu den bislang vorwiegend eingesetzten REST-APIs bietet GraphQL einige Vorteile, die im folgenden Abschnitt erläutert werden. Um beide Technologien besser vergleichen zu können, wird zunächst die Funktionsweise beider kurz beschrieben.

Eine REST-API besteht aus einer Reihe von Endpunkten, deren Anzahl davon abhängt, welche Daten der Client abfragen kann. Jeder Endpunkt ist einer Entität zugeordnet und gibt Informationen zu dieser Entität an den Client zurück. Möchte ein Client Informationen zu mehreren Entitäten abfragen, muss er für jede Entität eine separate Anfrage an den jeweiligen Endpunkt senden. Im Vergleich zu GraphQL ist dies sehr ineffizient und verursacht einen erhöhten Verwaltungsaufwand.

Bei GraphQL gibt es nur einen einzigen Endpunkt, über den der Client kommuniziert. Der Client stellt eine Anfrage und erhält eine Antwort. Diese umfassende Auskunftsfähigkeit von GraphQL ist Stärke und Schwäche zugleich. Eine REST-API begrenzt die Informationen, die mit einer einzigen Anfrage abgerufen werden können, indem sie den Umfang eines Endpunkts beschränkt. GraphQL hingegen unterstützt beliebige Abfragen über die Daten, sodass eine einzige Anfrage eine große Menge an Daten liefern kann.

Schema von GraphQL

Zur Beschreibung der Daten verwendet GraphQL ein sogenanntes Schema. Das Schema legt genau fest, welche Abfragen und Mutationen den Clients zur Verfügung stehen.

Darüber hinaus gibt es das sogenannte Introspektionsschema, mit dem Sie eine GraphQL-Anwendung nach Informationen zu den unterstützten Abfragen befragen können. Das Introspektionsschema lässt sich mit der folgenden Abfrage ausgeben. Zum Abfragen des Introspektionsschemas können Sie auch verschiedene GraphQL-IDEs oder beispielsweise GraphQL Voyager verwenden.

Schwachstellen und wie man sie verhindern kann

Laut der OWASP Foundation zählen die folgenden Angriffe zu den häufigsten gegen GraphQL:

  • Injection -- dazu gehören unter anderem SQL- und NoSQL-Injection, OS-Command-Injection, SSRF (Server Side Request Forgery) sowie CRLF-Injection (Carriage Return Line Feed) und Request Smuggling
  • DoS (Denial of Service)
  • Ausnutzen schwacher Autorisierung
  • Batching-Angriffe -- eine GraphQL-spezifische Variante des Brute-Force-Angriffs
  • Missbrauch unsicherer Standardkonfigurationen

Injektion

GraphQL selbst bietet keinen Schutz vor Injection-Angriffen. Wurde kein entsprechender Schutz eingebaut -- etwa durch parametrisierte Abfragen --, kann die Anwendung für jede Art von Injection anfällig sein. Daher sollten Sie alle eingehenden Daten validieren, um sicherzustellen, dass nur gültige Werte zugelassen werden. Ungültige Eingaben sollten stets abgelehnt werden, ohne dabei übermäßig viele Informationen über die Funktionsweise der API preiszugeben. Verwenden Sie im Backend parametrisierte Abfragen, um die vom Benutzer übermittelten Daten sicher zu verarbeiten. Stellen Sie zudem sicher, dass der Client die Daten aus der GraphQL-Antwort vor dem Rendering bereinigt. Die Implementierung einer geeigneten Content Security Policy ist darüber hinaus grundsätzlich empfehlenswert.

Denial of Service

DoS ist ein Angriff auf die Verfügbarkeit und Stabilität der API, der dazu führen kann, dass diese langsam reagiert, nicht mehr erreichbar oder vollständig ausfällt. Es empfiehlt sich daher, eine Paginierung einzubauen, um die Datenmenge pro Antwort zu begrenzen. Zusätzlich ist der Einsatz eines Rate Limiters pro Benutzer oder pro IP-Adresse sinnvoll.

Ausnutzen schwacher Autorisierung

Das Ausnutzen einer schwachen Autorisierungslogik ist mit Abstand das häufigste Problem bei GraphQL-basierten Anwendungen. Grundsätzlich ist es wichtig, robuste Authentifizierungs- und Autorisierungsmechanismen zu implementieren. Jede Client-Anfrage sollte daraufhin geprüft werden, ob der Client berechtigt ist, die angeforderten Daten abzurufen.

Batching-Angriffe

GraphQL unterstützt das Zusammenfassen von Anfragen -- auch bekannt als Query Batching. Damit kann der Client mehrere Abfragen für verschiedene Objektinstanzen in einem einzigen Aufruf bündeln. Dies ermöglicht sogenannte Batching-Angriffe, eine spezielle Form des Brute-Force-Angriffs. Um diese Angriffsart zu verhindern, sollten Sie das Batching für sensible Objekte wie Benutzernamen, E-Mail-Adressen, Kennwörter, OTPs und Sitzungs-Tokens unterbinden. Dadurch wird ein Angreifer gezwungen, die API wie eine REST-API anzugreifen und für jede Objektinstanz einen separaten Netzwerkaufruf durchzuführen. Darüber hinaus sollten Sie die Anzahl gleichzeitig ausführbarer Anfragen begrenzen.

Missbrauch von unsicheren Standardkonfigurationen

Ein typisches Beispiel sind sogenannte "versteckte" API-Endpunkte. Diese werden häufig für Funktionen bereitgestellt, die nicht öffentlich zugänglich sein sollen. Solche Endpunkte sind grundsätzlich problematisch -- sind sie jedoch ohne entsprechende Autorisierung erreichbar, wird das Risiko erheblich größer, insbesondere im GraphQL-Umfeld.

Um die Entwicklerfreundlichkeit zu fördern, bietet GraphQL die sogenannte Introspektion, die in den meisten Implementierungen standardmäßig aktiviert ist. Sie ermöglicht es API-Clients, dynamisch Informationen über das Schema abzufragen -- einschließlich der Dokumentation und der Typen für jede definierte Abfrage und Mutation. Auch Entwicklungswerkzeuge wie die GraphiQL IDE nutzen diese Funktion, um das Schema dynamisch abzurufen. Ist die Introspektion aktiviert, kann ein Angreifer das gesamte GraphQL-Schema einsehen und so die Angriffsfläche der API besser verstehen.

Wenn Sie auf eine GraphQL-API stoßen, besteht der erste Schritt in der Regel darin, eine Introspektionsabfrage auszuführen, um eine Kopie des Schemas zu erhalten. Dieses Schema hilft dabei, die Angriffsfläche der exponierten API zu verstehen.

Der sicherste und einfachste Ansatz ist, Introspektion und GraphiQL systemweit zu deaktivieren. Zusätzlich sollten Sie die eingebaute Funktion deaktivieren, die einen Hinweis zurückgibt, wenn ein angegebener Feldname einem existierenden Feld ähnelt, aber fehlerhaft ist. Ebenso sollten Sie detaillierte Fehlermeldungen wie Stack-Traces unterdrücken, um zu verhindern, dass ein Angreifer wertvolle Informationen über das System erhält.

Fazit

In diesem Beitrag haben wir die grundlegende Funktionsweise und die Sicherheitsanforderungen von GraphQL beleuchtet. Authentifizierung und Autorisierung sind die ersten Herausforderungen, die es zu bewältigen gilt. Darüber hinaus haben wir gezeigt, wie Sie gängige GraphQL-bezogene Angriffsflächen gezielt reduzieren können.

Quellen zum Üben

Um die beschriebenen Angriffsmöglichkeiten in der Praxis zu üben und nachzuvollziehen, finden Sie nachfolgend einige hilfreiche Ressourcen.

Damn Vulnerable GraphQL Application

TryHackMe - GraphQL Room