GraphQL-Sicherheit mit statischer Analyse und Snyk Code verbessern
Sam Sanoop
12. April 2022
0 Min. LesezeitGraphQL ist eine 2015 von Facebook entwickelte API-Abfragesprache. Seitdem haben ihre besonderen Funktionen und Möglichkeiten sie zu einer überzeugenden Alternative zu REST-APIs gemacht. In puncto Sicherheit können GraphQL-Server verschiedene Fehlkonfigurationen aufweisen, die zu Datenlecks, Problemen mit der Zugriffskontrolle und anderen Schwachstellen mit hohem Risiko führen.
Sicherheitsprobleme mit GraphQL sind zwar weithin bekannt, doch gibt es nur wenige Informationen dazu, wie sie sich ohne dynamische Analyse aufspüren lassen. In diesem Beitrag erfahren Sie, wie häufige GraphQL-Schwachstellen im Code auftreten und wie Sie sie mithilfe von Tools zur statischen Analyse und GraphQL Security finden. Da viele weit verbreitete GraphQL-Frameworks im npm-Ökosystem angesiedelt sind, konzentrieren wir uns auf Beispiele aus dem Node.js-Ökosystem.
Taint-Analyse in GraphQL-Frameworks
SQL-Injection- und Deserialisierungs-Schwachstellen wurden in zahlreichen Studien zu GraphQL-Endpunkten gemeldet. Ein Beispiel dafür findet sich in einem Bericht von HackerOne, in dem eine SQL-Injection über einen GraphQL-Parameter auftritt.
Wie Parameter von REST-APIs sind GraphQL-Argumente eine Quelle für nicht vertrauenswürdige Daten, über die Nutzereingaben in eine Anwendung gelangen können. Tools zur statischen Analyse sollten diese Parameter in einer Anwendung zuverlässig erkennen und modellieren können.
In GraphQL-Frameworks bilden Resolver die Verbindung zwischen Schema, Funktion und Argumenten, bevor diese an Resolver-Funktionen weitergegeben werden. Das folgende Beispiel zeigt das Argument args als Objekt, das alle GraphQL-Argumente enthält, die von der GraphQL-Operation für das Feld übergeben wurden.
Diese args-Ausdrücke lassen sich von der Engine Snyk Code nachverfolgen. Sie nutzt Points-to-Analyse und Typzustandsanalyse, um die Programmausführung präzise zu erfassen. Die Snyk Code-Analyse von SonicJS, einem modernen, auf Node.js basierenden Open-Source-Content-Management-System, ist ein hilfreiches Beispiel.
SonicJS ermöglicht Nutzern die Ausführung von CMS-Operationen über den GraphQL-Endpunkt. Eine solche Operation ist die Mutationsoperation fileUpdate, mit der Nutzer ihre Dateien aktualisieren können.
Diese Mutationsabfrage übernimmt vom Nutzer bereitgestellte Eingaben namens args.filePath und args.fileContent und übergibt sie anschließend an die Funktion writeFile des Objekts fileService. Die Implementierung der Funktion des Objekts fileService befindet sich in server/services/file.service.js und ist unten zu sehen.
Diese Funktion übernimmt beide GraphQL-Argumente und verwendet die Funktion fs.writeFile, um die Datei unter dem angegebenen Pfad zu aktualisieren. Sie kann jedoch ausgenutzt werden, um das angegebene Anwendungsverzeichnis zu durchlaufen und an beliebiger Stelle im Zielsystem eine neue Datei anzulegen, wie die folgende GraphQL-Abfrage zeigt:
Diese Schwachstelle ermöglicht die Ausführung von Code auf dem System, indem eine der SonicJS-Service-Dateien mit schädlichem JavaScript überschrieben wird, das beim Start oder Neustart vom SonicJS-System geladen wird. Das folgende Beispiel verwendet etwa die Funktion child_process, um eine Hintertür in der Anwendung einzurichten und über das auf dem Zielsystem installierte Programm ncat eine Verbindung zu einer vom Angreifer kontrollierten IP-Adresse herzustellen.

Der Bericht von Snyk Code zu dieser Schwachstelle ist unten zu sehen:

SonicJS kann dieser Schwachstelle künftig vorbeugen, indem für die Abfrage eine Authentifizierung und Autorisierung verlangt und der angegebene Dateipfad überprüft wird, damit Sonderzeichen wie ../ nicht zulässig sind.
GraphQL-Introspektion
Mit dem Introspektionssystem von GraphQL lässt sich ermitteln, welche Abfragen ein GraphQL-Server unterstützt. Dazu gehören Typen, Felder, Abfragen, Mutationen und weitere Informationen zum GraphQL-Schema.
Introspektion ist zwar eine Funktion und kein direktes Sicherheitsproblem, kann aber häufig dazu verwendet werden, verborgene Funktionen zu finden, die Angreifer ausnutzen können.
Im Node.js-Ökosystem ist die Introspektion in JavaScript-Frameworks oft standardmäßig aktiviert, was für Entwickler nicht immer ersichtlich ist. Wird das GraphQL-Framework ohne Angabe von Einstellungen verwendet, wie im folgenden Beispiel mit express-graphql, ist die Introspektion daher automatisch aktiviert.
Ein Beispiel für diesen Bericht in Snyk Code ist unten zu sehen:

Da es legitime Anwendungsfälle geben kann, in denen Introspektion für eine Produktionsanwendung erforderlich ist, wurde dieses Problem als geringes Risiko eingestuft.
Um die Introspektion in express-graphql zu deaktivieren, verwenden Sie NoSchemaIntrospectionCustomRule aus graphql-js.
Introspektion in der Produktionsumgebung kann zwar zu Sicherheitsproblemen führen, wird aber oft für die Entwicklung benötigt. Die Entwickler von ApolloServer haben dieses Problem gelöst, indem sie die Introspektion abhängig vom Produktionsstatus aktivieren oder deaktivieren.
Wenn Sie ein anderes GraphQL-Framework verwenden, können Sie mit einer Bibliothek eines Drittanbieters wie dem Paket graphql-disable-introspection Regeln für Ihren GraphQL-Endpunkt überprüfen.
Denial-of-Service-Angriffe auf GraphQL
Jede Abfrage weist eine Verschachtelungstiefe von Objekten auf, die von einem GraphQL-Endpunkt verarbeitet werden können. Die meisten GraphQL-Frameworks verfügen standardmäßig über keine Begrenzung der Abfragetiefe. Abfragen mit unbegrenzter Tiefe können das Framework anfällig für Denial-of-Service-Angriffe (DoS) machen, wie das folgende Beispiel zeigt:
Damit dieses Problem jedoch ausnutzbar ist, muss der GraphQL-Server ein rekursives Muster von Feldtypen aufweisen, bei dem eine wechselseitige Beziehung besteht. Ein Beispiel für diesen Bericht in Snyk Code ist unten zu sehen:

Diese DoS-Schwachstelle wurde in mevn-cli gefunden. Um sie zu beheben, kann das über npm verfügbare Paket graphql-depth-limit wie folgt verwendet werden:
Sehen Sie sich diesen Commit im mevn-cli-Repository an, um ein Beispiel für diese Korrektur zu erhalten.
Eine weitere Möglichkeit, DoS-Angriffe zu verhindern, besteht darin, die Länge des Anforderungstexts an Ihrem GraphQL-Endpunkt zu überprüfen. Lange Abfragen können auf DoS-Angriffe hindeuten. Die Abfragelänge zu überwachen, ist daher eine einfache und wirksame Prüfmethode.
GraphQL-Injection
Durch die Möglichkeit, eine Anwendungsabfrage zu manipulieren, kann eine GraphQL-Injection Angreifern Zugriff auf Daten verschaffen, die sie normalerweise nicht abrufen könnten – darunter Nutzerdaten und alle anderen Daten, auf die die Anwendung zugreifen kann. In vielen Fällen lassen sich diese Daten ändern oder löschen, was dauerhafte Auswirkungen auf Inhalt und Verhalten der Anwendung hat.
@octokit/core ist eine minimalistische Bibliothek, mit der sich die REST-API und die GraphQL-API von GitHub zum Erstellen von GraphQL-Abfragen nutzen lassen. Wenn Nutzereingaben zum dynamischen Erstellen einer GraphQL-Abfrage verwendet werden, kann ein Angreifer diese Abfrage möglicherweise so verändern, dass er auf vertrauliche Informationen zugreifen kann. Ein Beispiel für dieses Problem ist unten zu sehen:
Ein Beispiel für diesen Bericht in Snyk Code ist unten zu sehen.

Um GraphQL-Injection zu verhindern, sollten Sie vom Nutzer eingegebene Parameter nicht direkt an eine GraphQL-Abfrage übergeben. Wenn direkte Nutzereingaben aus Performance-Gründen erforderlich sind, überprüfen Sie sie anhand einer sehr strengen Zulassungsliste erlaubter Zeichen. Vermeiden Sie dabei Sonderzeichen wie ? & / < > ; - sowie Leerzeichen. Verwenden Sie nach Möglichkeit außerdem eine vom Anbieter bereitgestellte Escape-Funktion.
Fazit
Snyk Code unterstützt derzeit die folgenden GraphQL-Frameworks mit verschiedenen Taint-Analysen und semantischen Regeln:
express-graphqlkoa-graphqlmercuriusapollo-servergraphql-js
Wir möchten die Unterstützung künftig auf weitere GraphQL-Schwachstellen ausweiten, etwa Probleme mit unsicheren Objektreferenzen, direkten Referenzen und der Zugriffskontrolle. GraphQL wird derzeit für JavaScript unterstützt. Wir möchten jedoch weitere Programmiersprachen und Codequalitätsregeln hinzufügen, um Probleme wie Batching-Angriffe und Abfragekomplexität zu adressieren.
Starten Sie mit Capture the Flag
Erfahren Sie in unserem virtuellen On-Demand-Workshop für Einsteiger, wie Sie Capture-the-Flag-Herausforderungen lösen.


