Zum Inhalt springen
BlogBerechnenSchützen Sie Ihren GraphQL Server vor übermäßigem Ressourcenverbrauch

Schützen Sie Ihren GraphQL-Server vor übermäßigem Ressourcenverbrauch

Illustration eines Balkendiagramms mit vielen Datenpunkten, die ein wellenförmiges Aussehen mit Text erzeugen: Verteidigen Sie Ihren GraphQL-Server gegen übermäßigen Ressourcenverbrauch.

GraphQL bietet die Flexibilität, genau die Ressourcen und Attribute anzufordern, die Sie benötigen - nicht mehr und nicht weniger. Dies steht im Gegensatz zu REST, das oft zu viele oder zu wenige Daten abruft. Diese Präzision macht GraphQL äußerst effizient. Darüber hinaus bietet GraphQL Standardmethoden zur Handhabung von Paginierung, was seine Flexibilität weiter erhöht. Allerdings können böswillige Benutzer diese GraphQL-Funktionen ausnutzen, was ein erhebliches Risiko für die Stabilität Ihres Servers darstellen kann.

In diesem Blog werden wir untersuchen, wie die Flexibilität von GraphQL gegen Sie verwendet werden kann. Wir konzentrieren uns speziell auf eine Schwachstelle, die in den OWASP API Security Top 10 hervorgehoben wurde: uneingeschränkter Ressourcenverbrauch. Wir werden auch praktische Schritte zum Schutz Ihrer Systeme vor dieser Art von Missbrauch diskutieren.

GraphQLs Antwort auf Over- und Underfetching

GraphQL wurde zum Teil entwickelt, um die Probleme des Überholens zu lösen, die normalerweise bei REST auftreten. Betrachten wir zum Beispiel eine Standard-E-Commerce-Datenbank mit Benutzern, Produkten und Bestellungen. Stellen Sie sich vor, dass Sie den Gesamtbetrag einer Bestellung mit einer Bestell-ID abrufen müssen. Mit REST würde diese GET-Anforderung an /orders/17 nicht nur den Dollarbetrag abrufen, sondern auch Folgendes:

  • Bestelldaten
  • Abrechnungsinformationen
  • Versandinformationen
  • Produktmengen
  • Steuer
  • Status der Bestellung
  • ... und mehr

Das ist zu viel verlangt.

Bei REST kommt es auch zu einer Unterabrufung, wenn Sie zusammengehörige Daten aus mehreren Ressourcen zusammenstellen müssen. Stellen Sie sich vor, Sie möchten eine Zusammenfassung mit dem Datum und dem Status einer Bestellung, den Namen und Beschreibungen aller Produkte in der Bestellung und dem Namen und der E-Mail-Adresse des Benutzers, der die Bestellung aufgegeben hat, anzeigen. Dazu müssten Sie mehrere Anfragen senden:

  • GET /bestellungen/17
  • GET /Produkte/1662527
  • GET /Produkte/9914188
  • GET /Produkte/3750021
  • GET /Produkte/7557109
  • GET /Produkte/6081142
  • GET /benutzer/3314

GraphQL war die Antwort auf diese REST-Mängel. Sie können genau das abfragen, was Sie brauchen, und zwar über alle zugehörigen Ressourcen hinweg. Um das oben Genannte zu erreichen, könnte Ihre GraphQL wie folgt aussehen:

query {
  order(id: "17") {
    date
    status
    products {
      name
      description
    }
    user {
      name
      email
    }
  }
}

Es ist so einfach und flexibel! Diese Flexibilität bedeutet jedoch auch, dass ein böswilliger Benutzer absichtlich zu viele Daten abrufen kann.

Missbrauch der Abfrageflexibilität

Die Abfragesyntax für GraphQL ermöglicht es Ihnen, mehrere Abfragen innerhalb derselben Anfrage durchzuführen. Wir könnten die obige Abfrage nehmen und etwas Ähnliches tun:

query {
  Q1: order(id: "17") {
    date
    status
    products {
      name
      description
    }
    user {
      name
      email
    }
  }
  Q2: order(id: "17") {
    date
    status
    products {
      name
      description
    }
    user {
      name
      email
    }
  }
}

Diesmal haben wir dieselben Daten angefordert wie bei der vorherigen Abfrage, nur dass wir sie zweimal angefordert haben. Natürlich wäre die Antwort doppelt so groß wie bei der einfachen Abfrage. Was aber, wenn wir die Abfrage 100 Mal in einer einzigen Anfrage wiederholen würden?

query {
  Q00: order(id: "17") {    …  }  Q01: order(id: "17") {    …  }  …  Q99: order(id: "17") {    …  }
}

Auf diese Weise haben wir eine Abfrage erstellt, die eine 100-mal so große Antwort wie unsere ursprüngliche Abfrage liefert. Eine gute Möglichkeit, diesen Angriff zu veranschaulichen, ist das folgende Bild von Cheeseburgern. Die Hamburgerbrötchen bilden die einzelne Anfrage, aber zwischen den Brötchen könnten sich Hunderte von Rindfleischpasteten befinden!

gefüllte Abfrage

Wenn ein böswilliger Benutzer diese Abfrageflexibilität missbrauchen würde, könnte der übermäßige Ressourcenverbrauch Ihren Server zum Erliegen bringen.

Missbrauch von Paginierungsfunktionen

GraphQL verfügt auch über einige Standardmethoden zur Handhabung der Paginierung. Ein gängiger Ansatz ist die Offset-basierte Paginierung, bei der der Aufrufer die Anzahl der zu holenden Elemente (Limit) und das Element, mit dem begonnen werden soll (Offset), angibt.

Eine Abfrage zur Rückgabe von Informationen aus einer Produktsuche könnte zum Beispiel so aussehen:

query {
  products(searchString: "shirt", limit: 8, offset: 0) {
    id
    name
    description
    sku
    category
    images {
      path
      alt_text
    }
    variations {
      name
      description
      cost
    }
  }
}

Was wäre, wenn wir die Paginierungsparameter so anpassen würden, dass stattdessen diese Abfrage ausgeführt wird?

query {
  products(searchString: "shirt", limit: 800, offset: 0) {    …  }}

Bei einer ähnlichen Reihe von Beispielen, die ich auf einer E-Commerce-Website getestet habe, habe ich die Antworten verglichen, die ich erhielt:

$ du response*.json
680496  response_big.json
333649  response_small.json

Man könnte meinen, dass die große Datei etwa 100 Mal so groß ist wie die kleine Datei, da das Limit auf 800 statt auf 8 gesetzt wurde. Die Suche hat wahrscheinlich nicht insgesamt 800 Ergebnisse geliefert (möglicherweise nur 16 bis 20).

Der Missbrauch der Paginierung ist ein weiteres Beispiel dafür, wie jemand GraphQL-Abfrageparameter manipulieren kann, um Ihren Server zusätzlich zu belasten. Durch die Ausnutzung dieser Funktion können Angreifer Ihren Server zwingen, viel größere Anfragen als beabsichtigt zu bearbeiten, was zu einer Erschöpfung der Ressourcen und einem Denial-of-Service (DoS) führen kann.

OWASP API4:2023 Unbeschränkter Ressourcenverbrauch

Was wir demonstriert haben, fällt unter die OWASP API Security Top 10, insbesondere API4:2023 Unrestricted Resource Consumption. Diese Schwachstelle tritt auf, wenn APIs bestimmte Arten von Interaktionen oder Anfragen nicht einschränken, wodurch der Server anfällig für DoS-Angriffe und andere Betriebsstörungen wird.

Wenn eine API eine übermäßige Abfrage oder Paginierung ohne Grenzen zulässt, kann dies zu einer Spirale des Ressourcenverbrauchs führen. Dies wiederum kann zu Leistungseinbußen oder sogar zu einem kompletten Serverausfall führen. Ohne angemessene Begrenzungen können diese Angriffe den Dienst unterbrechen. Dies kann zu hohen Betriebskosten, zur Abwanderung von Kunden und zu Geschäftseinbußen führen.

Wie Sie sich schützen können

Um diesen Risiken zu begegnen, müssen Sie API-Anfragen angemessen regulieren. Implementieren Sie Kontrollen, die die Menge der anzufordernden Daten begrenzen. Dazu gehören Begrenzungen der Größe und Anzahl der Abfragen sowie die Implementierung von Ratenbegrenzungen und anderen Schutzmaßnahmen.

Hier sind einige praktische Vorschläge, wie Sie sich schützen können:

  • Größenbeschränkungen für die Nutzdaten von Anfragen und Antworten: Indem Sie die Größe der Daten, die angefordert und zurückgegeben werden können, begrenzen, können Sie verhindern, dass zu große Abfragen Ihren Server überfordern.
  • Paginierungsgrenzen: Implementieren Sie eine Höchstgrenze für die Paginierung, um sicherzustellen, dass ein Aufrufer nicht versucht, mehr Datensätze abzurufen als sinnvoll ist.
  • Web Application Firewall (WAF): Eine WAF kann dabei helfen, bösartige Aktivitäten zu erkennen und zu blockieren, um potenzielle Angriffe auf Ihre GraphQL-API zu vereiteln. Erwägen Sie die Verwendung einer WAF wie Haltdos von Linode Marketplace, um diese zusätzliche Sicherheitsebene hinzuzufügen.
  • API-Sicherheitswerkzeuge: Tools, die bösartige Aktivitäten erkennen und abschwächen können, sind unerlässlich. Sie können dabei helfen, ungewöhnliche Muster zu erkennen, die auf einen Angriff hindeuten, und ermöglichen es Ihnen, Maßnahmen zu ergreifen, bevor Ihr System beeinträchtigt wird.

Mit diesen Schritten können Sie das Risiko, dass Ihr GraphQL-Server durch übermäßigen Ressourcenverbrauch ausgenutzt wird, erheblich verringern. Wenn Sie sicherstellen, dass Ihre API-Interaktionen ordnungsgemäß geregelt sind, können Sie die Stabilität und Leistung Ihres Servers aufrechterhalten.

Weitere Informationen zum Bauen mit GraphQL finden Sie unter GraphQL Apollo: Eine Einführung mit Beispielen in unseren Dokumentationen.

Kommentare

Kommentar abgeben

Ihre E-Mail Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit *gekennzeichnet