GoldenEye-Angriff: Wie er funktioniert – und wie Sie Ihre Abwehr dagegen prüfen

Unterschiedlich getarnte Tokens schlüpfen durch eine Filtermembran – GoldenEye umgeht den Cache mit zufälligen Query-Parametern

· 14 Min. Lesezeit

Ein CDN hat die Aufgabe, dafür zu sorgen, dass die meisten Anfragen den Ursprungsserver nie erreichen. Ein GoldenEye-DDoS-Angriff ist darauf ausgelegt, dass jede einzelne ihn erreicht. Er hängt an jede Anfrage einige zufällig erzeugte Query-String-Parameter an – genug, damit sie für den Cache jedes Mal ein völlig neues Objekt ist. Ein Cache, der eine URL noch nie gesehen hat, hat nichts auszuliefern und fragt beim Ursprungsserver nach.

Damit verschiebt sich, wer hier eigentlich geprüft wird. Der Netzrand nimmt den Datenverkehr weiterhin an und meldet unauffällige Werte, während dahinter Ihre Applikationsserver jede Seite von Grund auf rendern und Ihre Datenbank jede Abfrage beantwortet – mit einer Rate, auf die Sie Ihre Kapazität nie ausgelegt haben, weil Sie mit dem Cache gerechnet haben. Ihr CDN arbeitet genau so, wie es konfiguriert ist. Es ist nur so konfiguriert, dass es den Angriff als sehr viele Besucher liest, die sehr unterschiedliche Inhalte verlangen.

Das Wichtigste in Kürze

  • Der Angriff richtet sich gegen Ihren Cache-Key, nicht gegen Ihre Bandbreite. Zwei bis fünf zufällige Parameter pro Anfrage machen aus einem Cache-Hit einen Cache-Miss, und jeder Miss ist ein vollständiger Weg zum Ursprungsserver und zurück.
  • Der Schaden entsteht tief im Stack. Ein langsamer Angriff bleibt am Webserver hängen. Dieser hier reicht bis in Ihren Anwendungscode und Ihre Datenbank, denn genau das kostet ein Miss.
  • Ob er wirkt, entscheidet die Konfiguration – mit zwei entgegengesetzten Antworten. nginx und Cloudflare nehmen den Query-String standardmässig in den Cache-Key auf; damit ist jede manipulierte URL ein Miss. Die CachingOptimized-Policy von CloudFront nimmt keinen einzigen Parameter auf; dieselben URLs teilen sich dort einen Key.
  • Jede Anfrage sieht wie ein Browser aus. Jedes Mal ein anderer, real existierender User-Agent, bei etwa der Hälfte zusätzlich DNT und Upgrade-Insecure-Requests. Eine Regel, die einen bestimmten schlechten User-Agent sperrt, findet keinen Ansatzpunkt.
  • Bei der Erkennung ist es umgekehrt. Jede Anfrage landet im Log, an Nachweisen fehlt es also nicht. Benennen lässt sich der Angriff über die Cache-Hit-Rate – und die steht selten auf dem Dashboard.

Dieser Beitrag gehört zu einer Serie über die zehn Simulationstypen, die Obsidio durchführt, einer pro Angriff. Jeder setzt an einer anderen Stelle Ihrer Abwehr an, weshalb ein Testprogramm alle Kategorien abdecken muss und nicht Volumen in einer einzigen. Wie sie zusammenspielen und wie Sie einen ersten Durchlauf aufbauen, steht in unserem Leitfaden dazu, wie Sie Ihren DDoS-Schutz testen.

Die zehn Simulationstypen

Ein Beitrag pro Typ, gruppiert wie auf der Plattform.

Angriffe auf der Anwendungsschicht (L7)

Langsame Angriffe

Verbindungserschöpfung

Protokollspezifisch & skriptgesteuert

Was ein GoldenEye-DDoS-Angriff tatsächlich macht

Die GoldenEye-Simulation von Obsidio ist ein HTTP-GET-Flood aus parallelen Pools, mit einer Ergänzung: Vor jeder Anfrage bekommt die Ziel-URL einen neuen Satz zufälliger Query-String-Parameter. Zwei bis fünf davon, mit Namen, die in einem Logfile ganz gewöhnlich wirken (cb, v, t, nocache und ähnliche), dazu zwei suchtypische Schlüssel wie q, page, ref oder utm_source.

Dazu kommt pro Anfrage eine Header-Schicht. Ist useRandomHeaders aktiv – der Standard –, wird der User-Agent für jede Anfrage aus einem Pool von acht echten Desktop- und Mobile-Browser-Kennungen gezogen. DNT: 1 und Upgrade-Insecure-Requests: 1 kommen bei jeweils rund der Hälfte hinzu, zufällig gestreut, so wie sich eine gemischte Browserpopulation verhält. Ein fester Satz geht bei allen mit: der Host, gewöhnliche Accept-Werte und Cache-Control: no-cache.

Dieser Header leistet weniger, als er verspricht. Eine no-cache-Anfrage ist bloss eine Bitte: RFC 9111 hält fest, dass der Client es vorzieht, eine gespeicherte Antwort nicht ohne erfolgreiche Validierung am Ursprungsserver zur Beantwortung der Anfrage heranzuziehen («indicates that the client prefers a stored response not be used to satisfy the request without successful validation on the origin server»). Ein Cache darf das ablehnen. Beim Query-String liegt der Fall anders, denn RFC 9111 bildet den Cache-Key mindestens aus der Request-Methode und der Ziel-URI – und die URI enthält den Query-String. Ihn zu ändern bittet den Cache nicht, seine Kopie zu übergehen, sondern verlangt eine Ressource, von der er gar keine Kopie hat.

Anders gesagt: ein HTTP-Flood, bei dem jeder Besucher eine andere Verkleidung trägt und beim Eintreten die Bestellnummer leicht abwandelt, damit der Laden nie sagen kann: «Die habe ich schon fertig, hier ist die Kopie.»

Welche Ihrer Schutzmassnahmen das hätte auffangen müssen

Gehen Sie die ganze Kette durch, denn die Antwort liegt selten bei der Massnahme, an die man zuerst denkt. Drei Gruppen zählen: was davor steht, was die durchgekommene Last abbekommt, und ob Ihnen überhaupt jemand Bescheid gibt.

Zone 1

Was fängt sie auf?

  • CDN und Cache am Netzrand. Der ganze Angriff zielt hierhin, und eine einzige Einstellung entscheidet den Durchlauf. nginx setzt proxy_cache_key standardmässig auf $scheme$proxy_host$request_uri; darin steckt der Query-String, jede manipulierte URL ist damit ein garantierter Miss. Cloudflares Standard-Key enthält den Query-String ebenfalls. Die Managed Policy CachingOptimized von CloudFront enthält keinen; derselbe Verkehr fällt dort auf einen Eintrag zusammen und verlässt den Netzrand nie. Von aussen sieht niemand, welcher Fall bei Ihnen gilt.
  • DDoS-Schutz und Scrubbing. Diesmal fliesst echtes Volumen, ein Schwellenwert hat also etwas, worauf er anspringen kann. Ob er rechtzeitig anspringt, ist die offene Frage.
  • Rate Limiting. Die Schwellenwerte greifen, aber ein Limiter, der die vollständige URL als Schlüssel verwendet, sieht in jeder Anfrage eine andere Ressource.
  • Bot-Erkennung und Challenges. Der Wechsel zwischen acht echten Browser-Kennungen entwertet Regeln auf Header-Ebene. Challenges schlagen sich besser.
  • Firewall und WAF. Sie sehen wohlgeformte GET-Anfragen ohne bösartigen Inhalt; es gibt also keine Signatur, die passt.

Zone 2

Was bekommt die Last ab?

  • Load Balancer oder Reverse Proxy. Cacht er selbst, trennt er nach derselben Key-Logik auf und erbt damit dieselbe Antwort.
  • Verbindungsebene. Zu den Anfragen kommt Handshake-Verkehr hinzu, weil standardmässig pro Anfrage ein neuer Socket aufgeht.
  • Webserver. Beschäftigt, aber selten der Engpass: Anfragen laufen durch und geben ihren Worker wieder frei.
  • Applikation und Datenbank. Hier trifft es. Jeder Miss ist ein vollständiger Rendervorgang: Templates, Sessions, Abfragen. Kapazität, die für Verkehr mit Cache-Unterstützung ausgelegt ist, bedient jetzt alles.
  • Auto-Scaling. Es sieht echte Last und skaliert – gewollt und teuer zugleich. Rechnen Sie durch, was eine Stunde davon kostet, bevor Sie es wissen müssen.

Zone 3

Würden Sie davon erfahren?

  • Dashboards. Die Anfragen pro Sekunde steigen, in der Kurve ist also etwas zu sehen. Benennen lässt es sich über die Cache-Hit-Rate, und die ist zwei Klicks entfernt.
  • Eine Prüfung von ausserhalb Ihres Netzes. Antwortzeiten am Netzrand können ordentlich aussehen, während sich am Ursprungsserver die Anfragen stauen.
  • Logging und Ihr SIEM. Alles landet im Access-Log. Die Arbeit ist das Gruppieren: Jeder Treffer bringt einen neuen User-Agent und eine nie gesehene URL.
  • Alarmierung. Sie hängt daran, ob überhaupt etwas die Anfragerate am Ursprungsserver oder die Cache-Hit-Rate beobachtet und nicht nur das Volumen am Netzrand.
  • Pikettdienst. Gerufen wird jemand, wenn es den Alarm überhaupt gibt. Ob das Runbook einen Flood erwähnt, der den Cache umgeht, liest man besser vorher nach.

Violett markiert, was sich nur mit einem Test auf Ihrer eigenen Infrastruktur klären lässt. Alles andere ergibt sich daraus, wie der Angriff funktioniert, und nicht daraus, wie gut Ihr Team konfiguriert hat.

Die letzte Gruppe fällt Teams erst spät auf. Eine Massnahme, die greift, aber unsichtbar bleibt, ist trotzdem ein Befund.

Was ihn von einem einfachen HTTP-Flood unterscheidet

Ein HTTP-Flood-Angriff und ein GoldenEye-Durchlauf sehen in der Bandbreitenkurve gleich aus und verhalten sich völlig unterschiedlich. Ein HTTP-Flood sendet Methode, URL und Body genau wie konfiguriert, ohne Zufallsanteil; ein Netzrand, der die Ziel-URL cacht, fängt ihn also ab. GoldenEye unterscheidet sich in zwei Punkten, und beide zählen für die Abwehr von DDoS-Angriffen auf Layer 7: Der Cache-Buster macht die Erreichbarkeit des Ursprungsservers zu einer Eigenschaft der einzelnen Anfrage, und die wechselnden Header nehmen Filtern, die auf die Form der Anfrage schauen, die Grundlage. Die Parameter sind schnell erklärt:

  • parallelRequestsPerWorker, Standard 20, Bereich 1 bis 100. Parallele Schleifen pro Worker. Die Zahl der cache-umgehenden Anfragen pro Sekunde steigt damit annähernd linear; die Plattform rechnet mit fünf pro Sekunde und Schleife, sofern das Ziel innerhalb von 200 ms antwortet.
  • useRandomHeaders, Standard true. Eingeschaltet: ein zufälliger Browser-User-Agent pro Anfrage aus dem Pool von acht. Ausgeschaltet: Alles hängt fest an GoldenEye/1.0 und lässt sich mühelos erkennen. Genau darin liegt der Sinn des Schalters – prüfen Sie damit, ob Ihre Header-Regeln überhaupt auslösen.
  • headers, Standard leer. Wird mit dem festen Satz und den Ergänzungen zusammengeführt; was Sie selbst setzen, belegt seinen Platz fest. Wer also DNT angibt, ersetzt damit die zufällige Beigabe.

Dazu kommt keepAlive, hier false und bei HTTP Flood true, und dieser Standard lohnt einen zweiten Blick. Ein HTTP-Flood bündelt Sockets, damit sich der Handshake auf viele Anfragen verteilt und die Last auf Applikationsthreads und Datenbank konzentriert. GoldenEye braucht das nicht, denn cache-umgehende URLs erreichen den Ursprungsserver, ob der Socket wiederverwendet wird oder nicht. Das Bündeln bringt nichts, was der Angriff nicht ohnehin schon hätte; also wird der Handshake jedes Mal bezahlt und der Verbindungsaufbau damit Teil der Last. Schalten Sie es ein, bleibt die Erreichbarkeit des Ursprungsservers erhalten, nur belasten Sie den Handshake-Pfad nicht mehr.

Wie Sie sich gegen einen GoldenEye-DDoS-Angriff wehren

Den Cache-Buster können Sie nicht sperren, weil sich Namen nicht aufzählen lassen, die sich jemand erst ausdenkt. Die Arbeit besteht darin, festzulegen, welche Parameter Ihren Cache-Key beeinflussen dürfen, und dafür zu sorgen, dass der Ursprungsserver den Rest aushält.

  • Normalisieren Sie den Cache-Key. Bei Cloudflare entfernt die Cache-Stufe «Ignore Query String» den Query-String aus dem Key; verfügbar ist sie in jedem Tarif, auch im kostenlosen. Die Steuerung einzelner Parameter sitzt in den Cache Rules und ist Enterprise. Bei CloudFront ist es eine Frage der Cache-Policy: Die Managed Policy CachingOptimized enthält weder Query-Strings noch Cookies. Bei nginx steht proxy_cache_key standardmässig auf $scheme$proxy_host$request_uri; den Query-String loszuwerden heisst, den Key aus $uri zu bauen.
  • Führen Sie eine Positivliste der erlaubten Parameter, statt einzelne zu sperren. Echter Verkehr auf einem Pfad nutzt eine kleine, bekannte Menge, und alles andere auszuschliessen begrenzt die Angriffsfläche. Cloudflare erlaubt in einem eigenen Cache-Key höchstens 100 Parameter. Der Preis ist die Korrektheit: Zwei verschiedene Antworten können sich dann einen Eintrag teilen, was Suche, Seitennavigation und alles Personalisierte unbrauchbar macht. Machen Sie es pro Pfad und aktivieren Sie dazu «Normalize URLs to origin», wie Cloudflare es empfiehlt, um Cache Poisoning zu vermeiden.
  • Bot-Management, das nicht an einem Header hängt. Eine Regel auf eine einzelne User-Agent-Zeichenkette scheitert an einem Pool von acht; Challenges und Verhaltenssignale überstehen den Wechsel. Am wichtigsten ist das dort, wo Caching nicht hilft: Cloudflare cacht HTML und JSON standardmässig nicht, ein Flood auf eine dynamische Seite erreicht den Ursprungsserver also unabhängig davon, wie Ihr Key aussieht.
  • Begrenzen Sie die Rate am Ursprungsserver nach Identität, nicht nach URL. Die URL ist jedes Mal einmalig; alles, was sie als Schlüssel verwendet, zählt bis eins. Verwenden Sie stattdessen Quelle, Session oder normalisierten Pfad als Schlüssel, und halten Sie den Ursprungsserver direkt unerreichbar – eine offen erreichbare IP-Adresse umgeht jede Massnahme darüber.

Was Sie selbst prüfen können und was dabei falsch herauskommt

Lesen Sie die Cache-Konfiguration und schicken Sie sich dann selbst eine Anfrage mit einem Unsinnsparameter und lesen Sie den Cache-Status, den Ihr CDN zurückmeldet. Billiger kommen Sie an keine brauchbare Antwort: Sie erfahren Pfad für Pfad, wie Ihr Key aussieht. Was Ihr Ursprungsserver tut, wenn dieser Key bei hoher Parallelität aus jeder Anfrage einen Miss macht, erfahren Sie damit nicht.

Prüfen Sie die Alarmierung getrennt davon. Ein synthetischer Alarm bestätigt die Alarmierungskette, ohne dass eine einzige Angriffsanfrage fliesst.

Fahren Sie einen Test aus einer einzigen Quelle gegen die Staging-Umgebung, mit Freigabe aus dem Change Management, auf Infrastruktur, die Ihnen gehört. Legitim, nützlich – und genau dort liegt die Falle.

Ein Test von einer einzigen Maschine lässt die Fragen aus Zone 1 nicht bloss offen. Er beantwortet mehrere davon falsch, und zwar beruhigend falsch. Ihr Rate Limit pro IP-Adresse fängt eine einzelne Quelle in Sekunden ab, die Bot-Erkennung markiert einen Client, der ungewöhnliche URLs abklopft, und die Reputationsfilter sperren die Adresse. Jede Massnahme in der vorderen Zone scheint zu greifen, Sie schreiben «abgewehrt» ins Protokoll – und der Befund, den Sie gebraucht hätten, ist genau der, den Sie nicht bekommen haben.

Dann kommt der echte Angriff von Tausenden IP-Adressen aus Privathaushalten, von denen keine einzige für sich einen Schwellenwert überschreitet, und dieselben Massnahmen verhalten sich anders, weil sie an der Streuung der Quellen und an der Realitätsnähe des Verkehrs ansetzen. Eine einzelne Maschine bildet beides nicht ab, und damit bleibt die Frage unbeantwortet, die über den Vorfall entscheidet: ob Ihr Ursprungsserver hält, wenn die Cache-Hit-Rate auf null fällt.

Wie Obsidio einen cache-umgehenden Flood testet

Obsidio führt GoldenEye als kontrollierte, autorisierte Simulation gegen Infrastruktur durch, die Ihnen gehört. Die Domain-Inhaberschaft wird per DNS-TXT-Eintrag verifiziert, bevor eine einzige Anfrage fliesst; die Last steigt stufenweise an, und jeder Durchlauf lässt sich jederzeit im Betrieb abbrechen. Sie bestimmen die Parallelität pro Worker, ob die Header zufällig gewählt werden und ob Verbindungen wiederverwendet werden. Weil die Last von über 100’000 weltweit verteilten echten Geräten kommt und nicht von einer Handvoll Instanzen im Rechenzentrum, treffen Rate Limits pro IP-Adresse und Reputationsfilter auf dieselbe Streuung der Quellen, die ein echter Angriff hat.

Zwei Messwerte zählen mehr als alle anderen:

  • Cache-Hit-Rate. Bricht sie mit dem Start des Durchlaufs ein, greift der Cache-Buster und Ihr Ursprungsserver bedient alles. Bleibt sie stabil, normalisiert Ihr Key die Parameter weg und der Netzrand fängt den Angriff ab – was schwarz auf weiss festzuhalten lohnt.
  • Anfragerate am Ursprungsserver. Derselbe Befund, gemessen dort, wo die Last ankommt. Vergleichen Sie sie mit dem, wofür Ihre Applikationsschicht ausgelegt ist, und beobachten Sie daneben die Auslastung des Datenbankpools und die Latenz der Abfragen.

Planen Sie die Fragen zur Erkennung mit ein. Obsidio kann berichten, wie Ihr Netzrand reagiert hat und was dort angekommen ist, weil sich das von aussen messen lässt. Ob Ihre Cache-Analytics den Einbruch gezeigt haben, ob Ihr SIEM etwas korreliert hat und ob jemand gerufen wurde, steht nur in Ihren eigenen Konsolen. Halten Sie also jemanden bereit, der sie während des Zeitfensters beobachtet.

Stärke wird bewiesen, nicht versprochen. Eine hohe Cache-Hit-Rate schützt Sie genau so lange, bis jemand eine URL schickt, die Sie noch nie gesehen haben.

Wo das in ein Testprogramm passt

GoldenEye gehört zu den Floods auf der Anwendungsschicht, neben HTTP Flood, Browser Flood und Apache Killer. Fahren Sie ihn direkt nach einem HTTP-Flood, dann isolieren Sie eine einzige Variable: Wird der HTTP-Flood abgefangen und GoldenEye nicht, liegt der Unterschied in Ihrem Cache-Key. Slowloris dreht hier fast alles um: kein Volumen, das die vordere Abwehr sehen könnte, Schaden, der am Verbindungspool endet, und Stille statt zu viel Lärm. Das ist das Argument dafür, alle zehn Simulationstypen abzudecken statt Volumen in einem einzigen.

Für regulierte Institute muss der Test auch einen Nachweis hinterlassen. Obsidio erzeugt kryptografisch attestierte Berichte, bei denen jede nachträgliche Änderung erkennbar ist, mit Zuordnung zu FINMA, DORA und NIS2 und erstellt in Trusted Execution Environments – am Ende eines Durchlaufs steht damit ein Beleg, den Sie ablegen können, und kein Screenshot, für den Sie bürgen müssen.

Um den Prüfumfang für eine autorisierte GoldenEye-Simulation gegen Ihre eigene Infrastruktur festzulegen, sehen Sie sich die Obsidio-Plattform an oder sprechen Sie mit dem Team. Unabhängig, neutral, überprüfbar: Resilienz, die Sie belegen können.

← Zurück zum Blog