Wie ich einen DDoS-Angriff (auf das Blog eines Freundes) überstanden habe

In: Vorgehen, Zukunft
Scrollen

Vor ein paar Tagen wurde das Blog eines Freundes mit DDoS-Attacken angegriffen. Es liegt auf einem von mir betreuten Server, auf dem sich auch diese Website befindet. Wie passend, das hier kurz zu reflektieren.

Als ich einen routinemäßigen Blick in die Log-Dateien warf, häuften sich genau in dem Augenblick Meldungen vom System: wahrscheinlich würde jemand gerade eine SYN-Flood-Attacke gegen den Server fahren. Zuerst dachte ich mir nicht wirklich etwas dabei. Gelegentlich findet es jemand einfach praktisch, mehrere Tabs—manchmal einige Dutzend—von einer Website gleichzeitig zu öffnen.

Die Fehlermeldungen wurden aber mehr und mehr mit der Zeit. Da wollte wohl jemand für ein wenig Unruhe sorgen. Mit einer Vermutung, was genau passiert, startete ich ein Überwachungsprogramm, mit dem ich live sehen konnte, welche Webseiten wie oft aufgerufen würden. Es dauerte nur ein paar Augenblicke, und der Bildschirm füllte sich mit einer Liste von hunderten von Anfragen die Minute auf das Blog von Jens. Da hatte es wohl jemand genau darauf und auf ihn abgesehen, und wollte das Hiking Blog mit unzählig vielen Anfragen lahm legen.

Wie würde der Server darauf reagieren?

Während ich mir schon einige Strategien zurecht legte, wie ich damit umgehen sollte, informierte ich ihn darüber, dass es vielleicht zu Aussetzern kommen könnte. Ich nutzte aber auch die Gunst der Stunde, diesen Angriff genauer zu studieren. Wie reagiert dieser Server auf diesen Ansturm? Wie schnell wirkt sich das auf die Verbindungsgeschwindigkeit aus? Wie stark werden die Prozessoren ausgelastet? Arbeitsspeicher? Vielleicht wäre ich sogar so mutig zu schauen, ab wann System-Dienste nicht mehr reagieren würden.

Ich sah, wie die Zahl der Anfragen ständig zunahm. Nach einer halben Stunde waren es etwas über tausend Anfragen die Minute. Bisher wirkte sich das aber nicht negativ aus: Sein Blog lud genauso schnell wie vorher. Auch der Server selbst war noch fern davon überlastet zu sein.

Vorsichtshalber stellte ich sicher, dass mein Web–Server (genauer: der vorgeschaltete Reverse–Proxy) sich auch ausreichend bei den System–Ressourcen bedienen darf, um möglichst viel aus dem Arbeitsspeicher zu liefern, damit wenig CPU–Last durch das Erstellen von Webseiten entsteht. Außerdem vergewisserte ich mich, dass er die in tausenden reinströmenden Log–Einträge nicht sofort auf die Festplatte schreibt, was sie sicherlich ganz schön belastet hätte, sondern erst nach einer gewissen Größe blockweise schreiben würde.

Dabei entdeckte ich, dass einige der Bilder in Jens’ Blog bei jedem Aufruf dynamisch erzeugt wurden. Das könnte ich doch optimieren. Ich änderte es so, dass auch diese zwischen gespeichert werden würden, schließlich enthalten sie keine Echtzeit–Informationen oder würden zur Anmeldung gebraucht. Und Optimierung des Zwischenspeichers? Da ginge doch sicher auch noch mehr. Um eine direkt etwas umfassendere Strategie zu fahren, veranlasste ich meinen Server, ältere Webseiten und Objekte länger im Zwischenspeicher verbleiben zu lassen.

Mit diesem kleinen Tuning startete ich den Web–Dienst neu, und beobachtete weiter die Last auf dem Server. Nach ein paar Minuten fanden sich auch alle Zombies wieder ein, die weiterhin etwas über tausend Anfragen die Minute stellten. Mein Server nahm es nach den Maßnahmen allerdings noch gelassener, und tat ohne Zucken weiter seinen Dienst.

Nach einer Stunde war Schluss mit den Angriffen.

In der Zwischenzeit schrieb ich Jens, dass dem Angreifer vielleicht langweilig wurde, weil keinerlei negative Reaktion hervorging—nicht vom Server, aber auch nicht von Jens oder mir in sozialen Kanälen. Gerade jedoch, als ich mich wieder anderen Dingen widmen wollte, rollte die nächste Welle von Zombies an.

Innerhalb von ein paar Minuten hatte ich etwas über zweitausend Zugriffe die Minute. Ich wurde etwas unruhig. Mein Server allerdings nicht, und lieferte weiterhin fröhlich seine Inhalte an die seelenlosen Besucher aus. Ich informierte Jens wieder darüber, aber dieses mal auch meinen Hoster über die Lage. Dann intensivierte ich meine Recherche, was bei DDoS-Angriffen noch getan werden kann, und ob ich Möglichkeiten finden sollte, die über das hinaus gehen würden, was ich selbst für den Notfall geplant hatte, ohne dass der Server, oder wenigstens der Web–Dienst, abgeschaltet werden müsste. Das wäre der letzte Schritt, den viele Anbieter bereits früh gehen würden. Ich nicht.

Also schaute ich, dass noch ein paar weitere Kleinigkeiten optimiert werden. Ich legte schon Regeln für die Firewall an, um die Anzahl gleichzeitiger Verbindungen eines Besuchers zu beschränken, und auch, wieviele Verbindungen über einen bestimmten Zeitraum hinweg aufgebaut werden dürften, bevor Verbindungen ganz unterbunden würden, aktivierte sie jedoch noch nicht. Ich stellte aber schon mal sicher, dass meine Verbindung über eine bestimmte IP-Adresse zum Server auf jeden Fall priorisiert werden würde—es wäre schon schwieriger, etwas zu bewirken, wenn ich selbst nicht mehr auf ihn zugreifen könnte.

Die Angriffe wurden aber nicht mehr, und für ungefähr eine Stunde hatte ich weiterhin etwas über zweitausend Zugriffe die Minute. Dann hörten sie auf. Der neue Server hatte seine erste Feuerprobe bestanden.

Dann informierte ich wieder Jens, der inzwischen verständlicherweise etwas besorgt und nun froh war, dass die Angriffe wieder einmal aufgehört hätten.

Natürlich nur vorübergehend.

Ich hielt die Konsole ständig offen, und konnte nach einiger Zeit sehen, dass die Zombies schon wieder zurück kamen. Und es waren mehr als vorher. Nach ein paar Minuten hatte ich über dreitausend Zugriffe die Minute. So langsam…

Allerdings war ich im entsprechenden Umfang erleichtert zu sehen, dass mein Server problemlos mit der steigenden Zahl der Zugriffe lineaer skalierte, und sich die Last noch immer in einem akzeptablen Rahmen befand. Nicht mal ein Viertel seiner Leistung wurde in Anspruch angenommen. Nur bei der Verbindung—genauer: die Zeit vom Aufruf bis zum Laden der ersten Bytes von Webseiten—kam es inzwischen häufiger zu Verzögerungen. Aber auch das hielt sich noch im vertretbaren Rahmen, schließlich luden die Webseiten im Schnitt noch immer schneller als viele andere.

Zum Vergleich mit den vorherigen beiden Wellen schaute ich mir das massive Untreiben ein paar Minuten an. Wie schon zuvor stieg die Zugriffszahl dann nicht weiter. Für ebenfalls eine Stunde durfte sich Jens weiter über die wohl etwas über dem Durchschnitt liegenden Zugriffszahlen freuen. Auch mit den erwähnten Aussetzern bei den Verbindungen tat der Server weiterhin fröhlich seinen Dienst, und nach ebenfalls einer Stunde ebbte die Welle fast so schnell ab wie sie gekommen war.

Ruhe. — Zumindest bis zum nächsten Tag.

Fast zur selben Uhrzeit wie am Vortag tummelten sich wieder Zombies vor der digitalen Haustüre. Sie brachten nun in etwa viertausend Anfragen die Minute mit sich.

Zwar war die Last auf meinem Server noch immer völlig in Ordnung, aber aus den gelegentlichen Verzögerungen im Verbindungsaufbau wurden regelmäßigere Verzögerungen. Die Bandbreite der Anbindung sollte wohl einfach nicht mehr länger mitspielen. Ich aktivierte die Notfallregeln der Firewall, und die Zahl der Verbindungsaufrufe pro Minute reduzierte sich schlagartig von über viertausend zu knapp über vierhundert.

Nur war ich nicht wirklich zufrieden mit der Lösung, auch wenn soweit alles unter Kontrolle war. Wieder eine Stunde später hörten auch diese Angriffe auf.

Damit die Benutzung des Servers erneut uneingeschränkt möglich war, deaktivierte ich die strikten Firewall-Regeln. Es verstrich einige Zeit, auch über die übliche Intervallzeit der Pausen hinaus. Ich telefonierte schon mit Jens, und wir waren recht froh, dass jetzt aber wohl Ruhe eingekehrt sei.

Bis sie wieder kamen. Und dann waren es sechstausend Aufrufe die Minute.

Schnell aktivierte ich wieder die Firewall–Regeln, und konnte diese Zahl um neun Zehntel auf sechshundert Aufrufe die Minute reduzieren. Und auch wenn mein Server jetzt bei etwas über einem Drittel bei der Auslastung und damit noch immer fern von „wirklich beschäftigt“ war, waren Verzögerungen beim Verbindungsaufbau nun der Normalfall. Langsam beeinträchtige das auch den E-Mail-Verkehr.

Zähneknirschend deaktivierte ich den Web–Dienst für das Hiking Blog, und wie zu erwarten gab es keinerlei Verbindungsprobleme mehr. Allerdings war das für mich alles, nur keine akzeptable Lösung, vor allem nicht unter den Umständen.

Also aktivierte ich den Web–Dienst wieder um mir ganz genau anzusehen, wo die Zombies her kamen. Ich sortierte die Liste der Zugriffe nach Zugriffshäufigkeit. Dann verweigerte ich jedem Besucher, der mehr als 20 Verbindungen gleichzeitig offen hatte, den zukünftigen Zugriff auf den Server. Doch wann immer ich ein paar ausgesperrt hatte, folgten umgehend neue Zombies, die entsprechende Plätze einnahmen.

Ich informierte Jens, dass ich sein Blog nun leider kurzzeitig vom Netz nehmen müsste. Anfragen, die auf sein Blog gestellt wurden, ließ ich auf den Anfragenden zurück lenken. Das wäre zwar ärgerlich für reguläre Besucher, aber solche, die versuchen, so viele Verbindungen wie nur irgendwie möglich aufzubauen, hätten vielleicht ein wenig Spaß. Außerdem würde ich so noch weiter sehen können, wer weiterhin versucht, das Hiking Blog durch so viele unnötige Anfragen lahm zu legen.

Weiter und weiter verbannte ich Zombies, die zu viele Anfragen stellten. Zwar sank die Netzlast ein wenig, aber nicht beträchlich. Kein Wunder bei der Zahl der Zombies. Oder? Ich hatte eine Idee.

Zuvor richtete ich aber noch ein, dass das Blog von Jens hoffentlich eher früher als später über einen Cloud–Dienst geladen werden sollte, der deutlich weniger Probleme mit der Bandbreite hat als mein Server—die Server-Last war ja kein Problem. Natürlich war das aber nicht meine Lösung, sondern nur kurzzeitiges Mittel zum Zweck.

Und dann? Dann entfernte ich in einem fast schon waghalsigen Manöver die strikten Firewall-Regeln, während ich die ban-Liste, die mittlerweile auf fast sechshundert Einträge gewachsen war, bestehen ließ. Innerhalb weniger Sekunden hatte ich über zwölftausend Anfragen die Minute, und zum ersten Mal überhaupt stieg die Server-Last auf knapp über fünfzig Prozent. Dann erstellte ich weniger strikte Firewall-Regeln, und regelte die Anfragen um ein Drittel auf achttausend Anfragen die Minute nach unten. Die Server-Last pendelte dabei bei etwas über vierzig Prozent ein.

Und dann ließ ich mir wie auch zuvor anzeigen, welche Zombies die meisten Verbindungen offen hatten—nun aber kombiniert mit der Bandbreite, die sie in Anspruch nahmen. Gezielt nahm ich mir diese vor, und verbannte sie von jedem Zugriff auf meinem Server. Nach schon nur knapp fünfzig ausgeschlossenen Rechnern implodierten die Anfragen die Minute auf dreihundert.

Vorbei war es mit den Verbindungsproblemen. Ich deaktivierte die (weniger) strikten Firewall-Regeln. Dann stiegen die Zugriffe zwar wieder auf sechshundert, von denen ich ja aber wusste, dass das alles andere als ein Problem für meinen Server sein sollte. Noch ein paar Hosts später waren es nur noch hundertzwanzig, und wohlwollend nahm ich zur Kenntnis, dass der Cloud–Dienst seine Arbeit aufgenommen hatte, und kräftig beisteuerte.

Ruhe. Diesesmal wirklich.

Schließlich verwehrte ich den letzten paar Dutzend nach und nach den Zugriff. Mit jedem verbannten Host verschwanden auch andere Zombies aus den Netzwerkzugriffen. Als ich schließlich bei achtzig Anfragen die Minute landete, stellte ich vor Erstaunen fest, dass der Cloud–Dienst zwar aktiv war, aber gar nicht die Anfragen auf die Startseite von Jens’ Blog zwischengespeichert sondern durchgereicht hatte. Nett.

Noch ein paar Einträge in der ban-Liste später war dann nun auch wirklich alles auf dem Server wieder normal. Zur Sicherheit konfigurierte ich den Cloud–Dienst noch zu Ende, damit wirklich alle Anfragen, falls noch welche nachkommen würden, nachdem ich mich endlich schlafen legte, nicht für irgendeinen Ausfall sorgen könnten.

Am nächsten Tag gab es zwar noch einmal einen kleinen Anlauf, den ich in den Statistiken vom Cloud–Dienst sehen konnte, aber nachdem ich eine Liste mit den Angreifern übermittelt hatte, war auch da Stille.

Nachbesprechung

Würde ich sagen, dass ich erfolgreich einen DDoS-Angriff abgewehrt habe? Ja. Aber nur den im speziellen. Eine allgemeine Lösung ist das nicht, und beim nächsten Angriff würde ich mir wohl wieder eine individuelle Lösung einfallen lassen müssen, wenn ich wieder auch einfach keine Downtime in Kauf nehmen oder den Schwarzen Peter einem anderen Dienstleister zuschieben will.

Hätte der Angreifer sich nur ein wenig mehr Mühe gegeben, und seine Zombie–Horde geschickter und zielgerichteter gelenkt—ich habe sehr schnell gemerkt, was meinem Server wirklich das Genick brechen würde—, wäre ich sicherlich nicht mit einer noch fast glänzender Rüstung davon gekommen, ohne eben einen der beiden oben genannten Wege zu gehen.

Anzumerken bleibt da noch, das ich gerade die technischen Details sehr vereinfacht dargestellt habe. Wer Details wissen möchte, kann mich gerne danach fragen.

Bemerkenswert auch, dass Botnets in 1000er Paketen wohl wirklich von jedem stundenweise gemietet werden können. Und da wird noch einiges passieren—ich kann nicht genug betonen, dass man sich mit diesem Szenario besser im Vorfeld beschäftigt:

Wenn es bereits passiert, ist es zu spät.