Zum Hauptinhalt springen
TIEMAN.IT
Zurück zum Blog

Wie ich einen Magento-Shop unter 600.000 Scraper-IPs am Laufen hielt

Kevin Tieman7 Min. Lesezeit
  • security
  • magento
  • ddos
  • ops

Letzte Woche bekam ich eine Nachricht von einem Kunden: "Der Shop fühlt sich langsam an, Kunden können nicht bezahlen". Ich loggte mich ein und sah, dass der Server fast lag. Fünf Cores, Load von 22. Cloudflare gab intermittierend 502 Bad Gateway an jeden zurück, der die Startseite öffnete.

Es war keine Störung auf unserer Seite. Ein externer Scraper hatte das Suchendpoint des Magento-Shops entdeckt und schickte mit 160.000 verschiedenen IP-Adressen gleichzeitig Anfragen dorthin. Am Spitzentag waren das über 530.000 Suchanfragen in 24 Stunden. Ein normaler Tag liegt bei rund 8.000 echten Besuchern. Das Verhältnis zwischen Mensch und Bot hatte sich in einem Schlag auf 4 Prozent Mensch, 96 Prozent Bot verschoben.

Unten lege ich dar, was genau passiert ist, was ich in den Logs gesehen habe, wie wir es gestoppt haben, ohne echte Besucher auszusperren, und was ich tun würde, wenn dein Shop morgen dasselbe erlebt.

Was ich in den Access-Logs sah

Das Muster war zu charakteristisch, um es auf einen unglücklichen Googlebot-Crawl zu schieben:

  • 94 Prozent aller Anfragen, die den Origin erreichten, gingen an einen einzigen Pfad: /catalogsearch/. Das ist die Suchfunktion. Nicht cacheierbar. Jeder Hit kostet einen PHP-Worker und eine aufwendige Elasticsearch-Abfrage.
  • Die Suchbegriffe waren unsere eigenen Marken- und Produktnamen, maschinell gefuzzt. Muster wie "marke produktcode 500ml", "marke produktcod 500ml", "mark produktcode 500ml" und "marke produktcode 500 ml". Tausende Permutationen, systematisch über mehrere Tage wiederholt.
  • Hinter jeder Anfragenserie steckte eine andere IP-Adresse. 70 Prozent der IPs machten nur zwei Anfragen, bevor sie rotierten. 15 Prozent eine. Keine einzige IP überschritt zehn Anfragen pro Minute.
  • Ein Drittel der IPs war IPv6, verteilt über Dutzende Consumer- und Mobil-ISPs weltweit. Das ist kein Rechenzentrum. Das ist ein Residential-Proxy-Netzwerk: gemieteter IP-Zugang über Verbrauchergeräte, die meist nicht wissen, dass sie genutzt werden.

Die Kampagne startete exakt um drei Uhr morgens an einem Dienstag, mit einem Sprung von zwölf auf fast 3.000 Anfragen pro Stunde. Zwischen 23:00 und 03:00 ist niemand wach, um einzugreifen, und der Angreifer wusste das.

Traffic-Grafik mit den einzigartigen Scraper-IPs pro Tag auf dem Suchendpoint, mit der Sprungfunktion am 27. Mai und dem Effekt der Cloudflare-Challenge am 4. Juni.

Warum das kein normaler DDoS war

Das Ziel war nicht, die Seite zum Absturz zu bringen. Die Beute waren die Produktdaten. Bei jeder Anfragenserie rief der Scraper die Suchergebnisseite ab, einschließlich der Preise in der Produktliste, und blätterte bis zu Seite 64. Nur 4,4 Prozent der Anfragen traf direkt eine Produktdetailseite. Alles wurde aus den Suchergebnissen herausgezogen.

Für den Angreifer sind 600.000 IPs kein Problem: Residential Proxies werden pro GB Verkehr abgerechnet, nicht pro IP. Für uns bedeutet das, dass klassische Abwehr nicht funktioniert. Per-IP-Rate-Limiting bringt nichts, wenn eine IP nur zwei Anfragen pro Minute macht. Captchas vor der Suchfunktion kosten uns echte Besucher. Ein Geoblock sperrt auch treue Kunden in Frankreich und Belgien aus, wo der Angreifer Menschen dafür bezahlte, ihre Verbindung zu teilen.

Der DDoS war ein Nebeneffekt. Der Server fiel aus, weil die Suchfunktion nun mal die schwerste Route in jedem Magento-Stack ist, und tausend gleichzeitige Anfragen pro Minute brechen eine Fünf-Core-Maschine.

Was wir getan haben, um es zu stoppen

Erste Maßnahme: Cloudflare auf "Under Attack Mode". Das ist eine JavaScript-Challenge vor jedem Besucher, und es wirkt sofort. Die Load sank von 22 auf 3. Aber Under Attack challenget auch Server-Webhooks. Tracking-Callbacks vom Logistikpartner, Zahlungsbestätigungen, Marketplace-Syncs: alles am Edge geblockt, weil ein Server kein JavaScript ausführt. Wir sahen es innerhalb einer Stunde in der Auftragsabwicklung: Trackingnummern kamen nicht mehr an.

Unverzichtbare Lektion: einen nuklearen Knopf lässt man nicht länger gedrückt als unbedingt nötig.

Was wir danach gemacht haben, in dieser Reihenfolge:

  1. Origin-Rate-Limit nur auf das Suchendpoint, nicht per IP sondern per Host. Der Angreifer rotiert IPs, also baut man ein Budget pro Shop statt pro Besucher. In nginx: limit_req_zone $host mit einem Burst, der echte Suchanfragen durchlässt.
  2. Cloudflare Managed Challenge auf der Such-URL, nicht seitenbreit. Ein Ausdruck wie (http.request.uri.path contains "/catalogsearch/" and not cf.client.bot) lässt verifizierte Suchmaschinen durch, challenged den Rest. Webhooks treffen es nicht.
  3. /catalogsearch/ auf noindex und robots-disallow gesetzt. Das verkleinert die Angriffsfläche und reduziert den Crawlbudget-Druck von legitimen Suchmaschinen auf einem Pfad, der sowieso keinen Suchverkehr liefern soll.
  4. Beweismaterial sichern. Nginx-Logs rotieren nach ein paar Tagen weg. Für die Anzeige habe ich jede Zeile, die mit dem Scraper zusammenhing, in eine separate CSV exportiert, mit Timestamps, IPs, Suchbegriffen und Statuscodes. 1,7 Millionen Zeilen in einer Datei, das ist dein Beweis.

Nach der Managed Challenge sanken die Scraper-Hits von sechs bis zehntausend pro Stunde auf achtzig bis 150 pro Stunde. Der verbleibende Verkehr war die Summe aus echten Besuchern, die legitim suchten, und Googlebot.

Was ich tun würde, wenn es bei deinem Shop passiert

Nicht warten, bis es vorüberzieht. Ein Residential-Proxy-Botnetz geht erst, wenn es kommerziell nicht mehr rentabel ist, deinen Katalog zu scrapen. Konkret:

Sofort, noch am selben Tag:

  • Cloudflare auf Under Attack Mode setzen (oder das Bot Fight Mode-Äquivalent deines Proxys), um aus dem akuten Druck herauszukommen. Akzeptieren, dass Webhooks vorübergehend nicht mehr ankommen.
  • Access-Logs der letzten 14 Tage an einem Ort sammeln. Logs rotieren, und ohne Logs hast du keine Anzeige.
  • Deinen Hosting-Partner anrufen. Nicht um Hilfe zu bitten (die können meistens nichts tun), sondern um sie zu informieren, dass ein Angriff läuft und ihr Monitoring übersteuern könnte.

Innerhalb des ersten Tages:

  • Identifizieren, welches Endpoint den Angriff bekommt. Ein awk auf deinem Access-Log zeigt, welcher Pfad den Top-Prozentsatz des Verkehrs auf sich zieht. In fast allen E-Commerce-Fällen ist das /catalogsearch/, eine Produktfilter-URL oder eine bestimmte Produktseite.
  • Ein Per-Host-Rate-Limit auf dieses Endpoint bauen, nicht per IP. Per IP funktioniert nicht bei Residential Proxies.
  • Die seitenbreite Challenge so schnell wie möglich durch eine gezielte Challenge auf diesem Endpoint ersetzen. Seitenbreite Challenges brechen Integrationen.

Während der Kampagne (die üblicherweise Tage dauert):

  • Anzeige erstatten. Die Justiz kann Proxy-Provider auf eine Art verpflichten, die einzelne Inhaber nicht können.
  • Das Angriffs-Endpoint auf noindex setzen, wenn es sowieso keinen SEO-Wert liefern muss.
  • Den Read-Timeout bei deinem php-fpm so begrenzen, dass eine langsame Anfrage keinen Worker 15 Minuten in Geiselhaft nimmt.

Wenn dein Shop auf einer Plattform läuft, die diese Knöpfe nicht bietet (Wix, Squarespace, manche Shopify-Templates), ist die Angriffsfläche kleiner, aber der Verteidigungsspielraum auch. In dem Fall ist "warten, bis der Angreifer aufhört" praktisch die einzige Option, und dein Hosting-Partner wird wahrscheinlich ein temporäres Ban auf den betroffenen Pfad setzen.

Was ich nicht gemacht habe

Origin-Firewalls, die nur Cloudflare-IPs zulassen, sind ein verlockender Knopf. Den benutzen wir nicht, weil er deinen Health-Monitor bricht, dein eigenes SSH wenn du es falsch konfigurierst, und das Problem nicht löst (der Angreifer kommt bereits durch Cloudflare). Dasselbe gilt für Cargo-Cult-Abwehr wie block_ua auf beliebige User-Agents: dieser Scraper läuft mit denselben Chrome-Strings wie deine echten Besucher.

Was ich wirklich gemacht habe, ist durchgehend live in den Logs mitzuschauen, während die Mitigierung ausgerollt wurde. Ein Angreifer, der sieht, dass seine Kampagne plötzlich 99 Prozent Fehlerrate hat, kann innerhalb einer Stunde die Taktik wechseln. Dreimal in vier Tagen haben wir das Rate-Limit angepasst, weil der Angreifer mehr IPs in den Pool warf. Ein Fix-and-Forget-Ansatz funktioniert nicht, wenn jemand aktiv gegen dich arbeitet.

Direkt reden?

Läuft gerade etwas auf deinem Webshop, dem du nicht traust, oder willst du ein zweites Augenpaar auf deine Logs? Schreib mir. Ich schaue innerhalb eines Werktages rein, kein Verkaufsgespräch.

Bereit loszulegen?

Kontaktiere mich für ein unverbindliches Gespräch über die Möglichkeiten.