Ein TLS-Flood-Angriff verlangt von Ihrem Server nichts. Er baut eine Verbindung auf, lässt den Server den vollständigen kryptografischen Handshake abschliessen und reisst die Verbindung dann ab. Keine Request-Zeile, kein Host-Header, kein Pfad. Nichts, was Ihre Web Application Firewall lesen könnte – eine Firewall, die Anfragen prüft, braucht eine Anfrage, die es gibt.
Genau das macht diesen Angriff unangenehm. Der Verkehr ist korrekt aufgebaut. Jede Verbindung ist eine legitime TLS-Verhandlung, die Ihr Server selbst zu Ende geführt hat. Die Kosten sind real, und sie fallen auf Ihrer Seite an, weil sich die Rechenarbeit der Public-Key-Kryptografie ungleich verteilt: Der Client wendet für die Anfrage kaum etwas auf, der Server für die Antwort sehr viel.
Das Wichtigste in Kürze
- Der Server zahlt, der Client kaum. Eigene Messungen von Obsidio setzen die serverseitigen CPU-Kosten eines abgeschlossenen Handshakes bei etwa dem Fünfzehnfachen der Client-Kosten an. Dieses Ungleichgewicht ist der ganze Angriff.
- Eine HTTP-Ebene gibt es nicht. Der Handshake wird fertig, und die Verbindung wird aufgegeben, bevor in irgendeiner Richtung ein Byte Anwendungsdaten fliesst.
- Eine WAF sieht davon nichts. Sie setzt an Anfragen an, also auf einer Ebene, die dieser Verkehr nie erreicht; sie anders zu konfigurieren hilft deshalb nicht.
- Entscheidend ist, wo Sie TLS terminieren. Handshakes, die auf einem CDN oder auf einem darauf ausgelegten Load Balancer landen, erreichen Ihren Ursprungsserver nie. Landen sie auf Ihrem Ursprungsserver, landen sie auf Ihrer CPU.
- Session Resumption ist nicht die Lösung, für die viele sie halten. Sie setzt einen Schlüssel aus einem früheren Handshake voraus, und eine neue Verbindung hat nichts, was sie wiederaufnehmen könnte.
Dieser Beitrag gehört zu einer Serie über alle zehn Simulationstypen, die Obsidio durchführt, ein Beitrag pro Angriff. Sie führen an ganz unterschiedlichen Stellen zum Ausfall, und deshalb braucht ein Testprogramm Abdeckung über die Kategorien hinweg statt Volumen in einer einzigen. Wie sie zusammenspielen, steht in unserem Leitfaden dazu, wie Sie Ihren DDoS-Schutz testen.
Die zehn Simulationstypen
Je ein Beitrag, gruppiert wie in der Plattform.
Angriffe auf der Anwendungsschicht (L7)
Langsame Angriffe
Verbindungserschöpfung
- TLS-Flood-AngriffSie sind hier
- TCP-Connection-Flood
Protokollspezifisch & skriptgesteuert
- DNS-Flood-Angriff
- Puppeteer-Script-Testsfunktionale Last, kein Angriff
Was bei einem TLS-Flood-Angriff tatsächlich passiert
Der Client baut eine TLS-Verbindung auf und lässt den Server die Verhandlung zu Ende führen: Schlüsselaustausch, Zertifikat, Sitzungsaufbau. In dem Moment, in dem die gesicherte Verbindung steht, läuft ein sehr kurzer Idle-Timeout ab, und die Verbindung wird abgerissen. Dann öffnet derselbe Slot die nächste. Der Server hat den teuren Teil erledigt und nichts darüber erfahren, was der Client wollte – der Client hat es nie gesagt.
Dieser Aufwand lässt sich genau benennen. Bei einem vollständigen TLS-1.3-Handshake sendet der Server seinen Key Share, sein Zertifikat und eine CertificateVerify-Nachricht, die RFC 8446 als Signatur über den gesamten Handshake mit dem privaten Schlüssel beschreibt («a signature over the entire handshake using the private key»). TLS 1.3 hat zudem die Cipher Suites mit statischem RSA und statischem Diffie-Hellman gestrichen; jeder vollständige Handshake enthält also einen ephemeren Schlüsselaustausch. Signieren mit dem privaten Schlüssel plus ephemere Schlüsselvereinbarung, einmal pro Verbindung – und das, bevor der Server irgendeine Vorstellung davon hat, ob die Verbindung es wert ist, bedient zu werden.
Der Client hat es leicht. Er erledigt seinen Teil des Schlüsselaustauschs, signiert nichts und verwirft die Sitzung Mikrosekunden später, ohne das Zertifikat zu prüfen. Eigene Messungen von Obsidio setzen die CPU-Kosten des Servers bei etwa dem Fünfzehnfachen der Client-Kosten an. Diese Zahl stammt aus unserer eigenen Instrumentierung und nicht aus einem veröffentlichten Standard; der Faktor verschiebt sich mit Schlüsseltyp, Cipher-Auswahl und der Frage, ob Offload-Hardware im Pfad sitzt. Die Richtung verschiebt sich nie.
Zwanzig Personen treten an eine Hochsicherheitstür. Die Wache führt bei jeder die vollständige Identitätsprüfung durch, jedes Dokument, jede Unterschrift. Jede dreht sich danach um und geht. Die Wache arbeitet sich an Besuchern ab, die nie eintreten, und hinterher gibt es keinen einzigen Besuchereintrag, weil niemand eingelassen wurde.
Die Benennung ist historisch gewachsen. Die interne Kennung bei Obsidio lautet ssl-flood, und breit diskutiert wird der Angriff weiterhin als SSL Flood. Umgesetzt ist er aber mit modernem TLS, mit Server Name Indication auf den Zielhost gesetzt.
Welche Ihrer Schutzmassnahmen das hätte abfangen müssen
Es lohnt sich, die ganze Kette abzugehen, die eine Verbindung durchläuft, denn die Antwort ist selten die Massnahme, die man erwartet. Drei Gruppen zählen: was vorgelagert ist, was das Durchgekommene auffängt, und ob Ihnen überhaupt jemand meldet, dass es passiert ist.
Zone 1
Hätte eines davon den Angriff stoppen müssen?
- DDoS-Schutz und Scrubbing. Die Bandbreite bleibt niedrig, ein Volumenschwellenwert ist also der falsche Auslöser. Fragen Sie Ihren Anbieter, ob er die Handshake-Rate pro Quelle beobachtet.
- Firewall und WAF. Eine WAF sieht davon nichts. AWS beschreibt die eigene als Überwachung der HTTP- und HTTPS-Anfragen, die an Ihre geschützten Webanwendungen weitergeleitet werden («the HTTP and HTTPS requests that are forwarded to your protected web application resources»). Weitergeleitet wird hier nie eine Anfrage.
- Rate Limiting. Setzt in der Regel an Anfragen an. nginx dokumentiert, dass eine Verbindung erst gezählt wird, wenn der Server eine Anfrage aus ihr bearbeitet und der vollständige Request-Header gelesen ist («only if it has a request being processed by the server and the whole request header has already been read»).
- Bot-Erkennung und Challenges. Eine Challenge wird in einer HTTP-Antwort ausgeliefert. So weit kommt hier nichts.
- CDN. Möglicherweise entscheidend, und zwar aus einem einzigen Grund: Es terminiert TLS. Caching spielt keine Rolle. Ob Ihr Ursprungsserver weiterhin auf seiner eigenen IP-Adresse antwortet, entscheidet die Sache.
Zone 2
Was bekommt die Last ab?
- Load Balancer oder Reverse Proxy. Fängt den ganzen Angriff ab, sofern er TLS selbst terminiert. Prüfen Sie, ob Ihrer das tut und ob nichts an ihm vorbeiläuft.
- Verbindungsschicht. Hier herrscht Wechsel statt Füllung. Sockets entstehen und verschwinden, die Tabelle sieht deshalb nie bedrohlich aus.
- TLS-Stack und CPU. Hier tut es weh. Asymmetrische Kryptografie pro Handshake, in der Rate, die die Geräteflotte durchhält.
- Anwendung und Datenbank. Bleiben unberührt, weil keine Anfrage zu ihnen geroutet wird.
- Auto-Scaling. Hängt an Ihrer Skalierungsmetrik. Skalieren Sie über die CPU, kann es reagieren; skalieren Sie über die Anfragerate, wacht es nie auf.
Zone 3
Würden Sie davon erfahren?
- Dashboards. Die Kurve der Anfragerate bleibt flach, die CPU-Kurve auf Ihren TLS-Terminatoren nicht. Ob überhaupt jemand auf die zweite schaut, ist der eigentliche Befund.
- Access-Logs und Ihr SIEM. Access-Logs entstehen pro Anfrage. Es gibt keine Anfragen, also bleibt hinterher kaum etwas zu korrelieren.
- Eine Prüfung von ausserhalb Ihres Netzwerks. Das Einzige, was diesen Angriff zuverlässig erkennt – sofern Sie eine betreiben.
- Alarmierung. Hängt davon ab, ob ein Schwellenwert für die CPU-Auslastung existiert und wo er liegt.
- Pikettdienst. Folgt aus dem Vorherigen. Wird kein Schwellenwert überschritten, wird niemand alarmiert.
Violett markiert, was sich nur mit einem Test auf Ihrer eigenen Infrastruktur klären lässt. Alles Übrige folgt aus der Funktionsweise des Angriffs und nicht daraus, wie sorgfältig Ihr Team konfiguriert hat.
Zone 3 fällt hier aus dem Rahmen. Das Signal existiert, auf einer CPU-Kurve, die die meisten Teams längst haben. Die Frage ist, ob es je jemand mit einem Alarm verknüpft hat.
Was Sie steuern, und worin sich das von einem TCP-Connection-Flood unterscheidet
Obsidio gibt vier Parameter frei; zwei davon verändern den Charakter des Durchlaufs:
- Parallele Handshakes pro Worker. Standardmässig zwanzig, einstellbar von eins bis hundert. Der Wert skaliert die gleichzeitige Handshake-Last linear.
- Idle-Timeout. Standardmässig eine Millisekunde. Bei dieser Einstellung wird die Verbindung praktisch im selben Moment abgerissen, in dem sie gesichert steht: Der Server zahlt die Kryptokosten, der Client geht. Erhöhen Sie den Wert, werden Sockets länger gehalten und belegen Ports und File Descriptors – zum Preis einer niedrigeren Handshake-Rate. Sie wählen damit zwischen Druck auf die CPU und Druck auf die Verbindungstabelle.
- Denkzeit. Eine Pause zwischen den Handshakes innerhalb jedes Slots, standardmässig null. Sie bremst den Durchlauf linear, wenn Sie ein gehaltenes Niveau statt einer Spitze wollen.
- Port. Standardmässig 443. Die Zertifikatsprüfung ist auf Client-Seite abgeschaltet; ein abgelaufenes oder selbst signiertes Zertifikat auf einem Test-Endpunkt bricht den Handshake also nicht ab.
Die beiden Angriffe stehen in derselben Kategorie und verhalten sich völlig unterschiedlich. Ein TCP-Connection-Flood-Angriff verhandelt über den TCP-Handshake hinaus nichts, sendet keine Nutzdaten und hält jeden untätigen Socket über Minuten; sein Ziel ist Ihre Verbindungstabelle, also File Descriptors, Einträge im Connection Tracking und die Accept-Queue. Ein TLS-Flood-Angriff ist das Spiegelbild: Seine Sockets leben Millisekunden, und sein Ziel ist Ihr Prozessor. Grosszügige Verbindungslimits bei schwacher CPU scheitern am TLS-Flood-Angriff und stecken einen Connection Flood problemlos weg; eine schnelle CPU hinter einem engen File-Descriptor-Limit verhält sich umgekehrt. Wer nur einen der beiden fährt und die Kategorie als abgedeckt verbucht, merkt das spät.
Wie Sie sich gegen einen TLS-Flood-Angriff verteidigen
Wo TLS terminiert wird, entscheidet fast alles. Fangen Sie dort an.
- Terminieren Sie TLS an einer Stelle, die auf Handshakes ausgelegt ist. Ein CDN oder ein Managed Load Balancer teilt den Pfad in zwei Hälften. Cloudflares Full-Modus dokumentiert genau diese Form: HTTPS zwischen Besucher und Cloudflare, wobei Cloudflare eine eigene Verbindung zum Ursprungsserver aufbaut. AWS dokumentiert dieselbe Struktur für einen Application Load Balancer, der zwei Verbindungen unterhält, eine zum Client und eine zum Ziel («maintains two connections: one connection with the client and one connection with a target»). Der übliche Vorbehalt gilt: Eine über Proxy geführte Website, deren Ursprungsserver weiterhin auf Port 443 antwortet, ist nicht geschützt, sondern nur verdeckt.
- Verbuchen Sie Session Resumption nicht als Gegenmassnahme. Sie ist ein Performance-Feature und leistet hier nichts. RFC 8446 erklärt, warum: Resumption nutzt eine Pre-Shared-Key-Identität, die der Server erst nach einem bereits abgeschlossenen Handshake ausgegeben hat, und nur dann kann der abgeleitete Schlüssel den kryptografischen Zustand anstelle eines vollständigen Handshakes aufsetzen («bootstrap the cryptographic state instead of a full handshake»). Eine Verbindung ohne vorherige Sitzung hat nichts vorzuweisen. nginx liefert
ssl_session_cache none,ssl_session_timeout 5mundssl_session_tickets onaus; all das betrifft wiederkehrende Nutzer, nicht Ihre Abwehrlage. - Prüfen Sie, auf welcher Ebene Ihre Verbindungslimits liegen. Das ist die Einstellung, die am häufigsten unbemerkt falsch gesetzt ist. nginx liefert zwei Limiter für Verbindungen pro Quelle. Der HTTP-Limiter zählt eine Verbindung erst, wenn ein vollständiger Request-Header gelesen ist, und bekommt diesen Verkehr damit nie zu sehen. Das Gegenstück auf Stream-Ebene, verfügbar seit nginx 1.9.3, zählt Verbindungen pro Schlüssel ohne diese Bedingung. Ist Ihre einzige Obergrenze pro Quelle die HTTP-Variante, liegt sie nicht in diesem Pfad.
- Messen Sie Ihre Handshake-Reserve, weil sie Ihnen niemand nennen kann. Handshakes pro Sekunde hängen vom Schlüsseltyp Ihres Zertifikats ab, von der Cipher-Auswahl, vom Prozessor und davon, ob Offload-Hardware im Pfad sitzt. Wir haben keine veröffentlichte Zahl gefunden, die es wert wäre, wiederholt zu werden, und erfinden keine. Ein verwandter Standardwert:
ssl_handshake_timeoutim Stream-Modul von nginx liegt bei sechzig Sekunden – das begrenzt langsame Handshakes und richtet gegen schnelle nichts aus.
Was Sie selbst prüfen können, und wo das in die Irre führt
Einiges davon können Sie heute ohne fremde Hilfe beantworten. Es lohnt sich zu wissen, wo eine billige Prüfung Sie täuscht.
Lesen Sie die Konfiguration. Stellen Sie fest, wo TLS terminiert wird, ob Ihr Ursprungsserver direkt auf seiner eigenen IP-Adresse antwortet und ob Ihr Limit für Verbindungen pro Quelle auf HTTP-Ebene oder darunter sitzt. Das kostet einen Nachmittag und sagt Ihnen, dass das Design stimmt. Es sagt Ihnen nicht, dass der Prozessor durchhält.
Prüfen Sie die Alarmierungswege separat. Lösen Sie einen synthetischen CPU-Alarm aus und sehen Sie nach, ob er beim richtigen Pikettdienst ankommt und ob jemand handelt. Damit ist der Meldeweg geprüft, und Angriffsverkehr braucht es dafür nicht.
Fahren Sie einen Test aus einer einzigen Quelle gegen eine Staging-Umgebung, mit Freigabe aus dem Change-Management, auf Infrastruktur, die Ihnen gehört. Das ist legitim und nützlich. Und genau hier liegt die Falle.
Ein Test von einer Maschine beantwortet die Fragen aus Zone 1 nicht bloss nicht – er beantwortet mehrere davon falsch, und zwar beruhigend falsch. Ihr Limit für Verbindungen pro Quelle greift bei einer einzelnen Adresse sofort. Reputationsfilter erledigen eine Rechenzentrums-IP mühelos. Auch das Ungleichgewicht arbeitet gegen Sie: Der Prozessor eines einzelnen Clients begrenzt, wie viele Handshakes er anstossen kann; die erreichte Spitze sagt also mehr über Ihre Testmaschine aus als über Ihre Abwehr. Jede Massnahme in Zone 1 scheint zu halten, und Sie schliessen daraus, dass Sie abgedeckt sind.
Dann trifft echter Verkehr von Tausenden IP-Adressen aus Privathaushalten in Dutzenden Ländern ein, keine einzelne Quelle tut etwas Auffälliges, und dieselben Massnahmen verhalten sich völlig anders – weil sie an der Konzentration der Quellen und an der Realitätsnähe des Verkehrs ansetzen. Eine Maschine bildet weder das eine noch das andere ab. Die billige Prüfung bescheinigt damit genau jenen Massnahmen ein Bestehen, denen Sie am meisten vertrauen müssen; und ein synthetischer Alarm sagt Ihnen nicht, ob jemand eine steigende Prozessorkurve als Angriff gelesen hätte und nicht als fehlerhaftes Deployment.
Wie Obsidio einen TLS-Flood-Angriff testet
Am Anfang steht die Autorisierung. Die Domain-Inhaberschaft wird vor dem ersten Verkehr über einen DNS-TXT-Eintrag geprüft, Durchläufe fahren stufenweise hoch, und jeder Durchlauf lässt sich im Betrieb abbrechen. Sie wählen die Parallelität, den Idle-Timeout und die Taktung. Die Last kommt von über 100’000 weltweit verteilten echten Geräten und nicht von einer Handvoll Instanzen im Rechenzentrum; eine Obergrenze pro Quelle wird damit so geprüft, wie verteilter Verkehr sie prüfen würde.
Zwei Grössen, auf die Sie achten sollten:
- Handshakes pro Sekunde, nicht Anfragerate. Jeder abgeschlossene Handshake zählt im Bericht als eine Anfrage; die Ratenangabe ist hier also eine Handshake-Rate. Vergleichen Sie sie mit der Reserve, die Sie vorher gemessen haben.
- Verbindungszahlen nach dem Handshake. Aktive und maximale Verbindungen zeigen, wie viele Sockets zwischen abgeschlossenem Handshake und Abbau stehen. Beim Standard-Idle-Timeout bleibt das auch unter voller Last niedrig, und eine niedrige Zahl neben einer hohen Handshake-Rate ist die Signatur dieses Angriffs und nicht die eines Connection Floods.
Diese Aufteilung sollte man klar benennen. Obsidio berichtet, wie viele Handshakes abgeschlossen wurden, wie viele fehlgeschlagen sind, wie Ihre Schutzmassnahmen am Netzrand reagiert haben und was die Verbindungszahlen gemacht haben – all das ist von aussen sichtbar. Ob die Prozessoren auf Ihren TLS-Terminatoren ausgelastet waren, ob Ihr SIEM etwas aufgezeichnet hat und ob jemand alarmiert wurde, sehen Sie nur auf Ihren eigenen Konsolen. Lassen Sie während des Zeitfensters jemanden dort mitschauen, sonst bleiben diese Fragen offen.
Stärke wird bewiesen, nicht versprochen. Ein TLS-Flood-Angriff verlangt von Ihrem Server nichts. Er verlangt von ihm, tausendfach zu beweisen, wer er ist, und geht dann ohne ein Wort.
Wo das in ein Testprogramm gehört
Der TLS-Flood gehört in die Kategorie Verbindungserschöpfung, zusammen mit dem TCP-Connection-Flood. Beide umgehen die Anwendung vollständig, und zusammen trennen sie zwei Fehlermodi, die Teams gewohnheitsmässig vermischen: Der eine erschöpft den Kryptopfad, der andere die Verbindungstabelle. Wer nur den zweiten prüft, lässt seine Handshake-Kapazität ungeprüft, und kein Test mit einer Flut auf der Anwendungsschicht schliesst diese Lücke, weil ein HTTP-Flood-Angriff die Handshake-Kosten über wiederverwendete Verbindungen verteilt.
Die zehn Simulationstypen führen an ganz unterschiedlichen Stellen zum Ausfall. Langsame Angriffe wie Slowloris hungern Ihren Verbindungspool aus, indem sie eine Anfrage nie abschliessen. Ein TLS-Flood-Angriff schliesst alles ab, was er beginnt, und geht. Entscheidend ist die Abdeckung über die Kategorien hinweg, nicht das Volumen in einer davon.
Für regulierte Institute muss der Test zudem einen Nachweis hinterlassen. Obsidio erstellt kryptografisch attestierte, manipulationssichere Berichte mit Zuordnung zu FINMA, DORA und NIS2, erzeugt in Trusted Execution Environments. Das Ergebnis eines Durchlaufs ist damit ein Beleg, den Sie ablegen können, und kein Screenshot, für den Sie bürgen müssen.
Um eine autorisierte TLS-Flood-Simulation gegen Ihre eigene Infrastruktur zu planen, sehen Sie sich die Obsidio-Plattform an oder nehmen Sie Kontakt auf. Unabhängig, neutral, überprüfbar: Resilienz, die Sie belegen können.
