Zuerst: Stellen Sie sicher, dass es wirklich ein Angriff ist
Der teuerste Fehler mitten in einem Ausfall ist, das Falsche zu behandeln. „Die Seite ist langsam“ ist ein Symptom, das eine echte Flut genauso auslöst wie ein Deploy, das eine Query ohne Index ausgeliefert hat, ein Cron-Job, der jede Stunde zur selben Minute anfängt, die Datenbank leerzuräumen, ein Crawler, der Ihre facettierte Suche entdeckt hat, ein Link, der es auf die Startseite von irgendwo Großem geschafft hat, und eine vollgelaufene Festplatte. Von einem Browser aus sehen alle diese Fälle identisch aus, und die richtigen Reaktionen schließen sich gegenseitig aus: Sie wollen keine echten Kunden ausbremsen, nur weil eine Migration einen Index vergessen hat.
Drei Fragen trennen sie in unter einer Minute. Ist das Verkehrsaufkommen wirklich abnormal, oder ist der Traffic normal und nur der Server langsam? Eine Flut zeigt sich als sprunghafte Veränderung bei Paketen oder Anfragen pro Sekunde; ein missglücktes Deploy zeigt sich als normales Anfragevolumen bei eingebrochener Antwortzeit. Hat sich in der letzten Stunde auf Ihrer Seite etwas geändert? Prüfen Sie das Deploy-Log vor der Firewall — selbstverschuldete Vorfälle übertreffen Angriffe auf kleiner Infrastruktur bei Weitem. Verteilt sich die Last über die ganze Seite, oder konzentriert sie sich auf einen einzigen Pfad? Echte Fluten sind meist wahllos oder zielen auf die Startseite; ein teurer Endpunkt, der von hundert Clients bombardiert wird, ist eher Missbrauch als ein DDoS-Angriff, und die Lösung dafür ist deutlich billiger.
Beantworten Sie das, dann geht es weiter. Der Rest dieses Guides geht davon aus, dass die Antwort lautete: Das Volumen ist abnormal, auf Ihrer Seite hat sich nichts geändert, und die Box geht unter.
SP·02Die Fünf-Minuten-Triage
Es gibt nur zwei Fehlerarten, die zählen, und sie verlangen entgegengesetzte Reaktionen. Entweder die Leitung ist voll — Pakete kommen schneller an, als Ihr Uplink oder Ihr Kernel sie verarbeiten kann, und Ihr Server verliert Traffic, bevor auch nur eine Ihrer Anwendungen ihn zu Gesicht bekommt —, oder die Leitung ist in Ordnung und die Anwendung ist erschöpft, weil wohlgeformte Anfragen schneller eintreffen, als sie beantwortet werden können. Beides zu verwechseln verschwendet die Stunde: nginx-Tuning bringt gegen eine gesättigte Leitung nichts, und mehr Bandbreite zu kaufen bringt gegen eine Anfragenflut nichts.
Unterscheiden Sie beide, indem Sie zwei Zahlen vergleichen. Sehen Sie sich die Interface-Counter und die CPU-Aufteilung gleichzeitig an. Wenn die rx-Bytes nahe an Ihrer Portgeschwindigkeit kleben, wenn die Zähler für dropped oder overrun steigen und die Zeit eher in Soft-Interrupts geht als in Ihre Anwendung, liegt die Flut auf Layer 3 oder 4 und ist ein Kapazitätsproblem. Ist die Bandbreite unauffällig, aber der Worker-Pool gesättigt, stauen sich die Verbindungen, und das Access-Log ist voller plausibel aussehender Anfragen, dann ist es Layer 7 und ein Filterproblem.
Klassifizieren Sie den Layer-3/4-Fall dann noch einen Schritt genauer, denn die Subtypen verhalten sich unterschiedlich. Eine SYN-Flut zeigt sich als Zehntausende halboffener Sockets in SYN-RECV; der Kernel kommt damit gut zurecht, sobald Syncookies aktiviert sind. Eine UDP- oder Amplification-Flut zeigt sich als riesiges eingehendes Volumen auf Ports, auf denen Sie gar nicht lauschen — DNS-, NTP-, Memcached-, CLDAP-Reflexionen —, und nichts, was Sie ausführen, hilft dagegen, weil der Schaden schon angerichtet ist, sobald die Pakete Ihre NIC erreichen. Eine Fragmentierungs- oder Rohpaket-Flut zeigt sich als hohe Paketrate bei moderater Bandbreite, was die CPU statt die Leitung aushungert. Notieren Sie sich, welche davon Sie haben, bevor Sie eine Konfigurationsdatei anfassen.
Was Sie nicht von innerhalb der Box aus reparieren können
Das ist der Teil, den die meisten Artikel auslassen, und der Teil, der darüber entscheidet, ob Ihre Stunde produktiv ist. Eine Firewall-Regel auf dem Ziel rettet keinen gesättigten Uplink. Ihr iptables-DROP läuft auf der Maschine am Ende der Leitung — das Paket hat den Transit-Link bereits durchquert, die Bandbreite, für die Sie bezahlen, bereits verbraucht, und bereits das Paket eines echten Nutzers verdrängt. Es lokal zu verwerfen schützt Ihre Anwendung davor, Zyklen zu verschwenden, was etwas wert ist, und schützt Ihre Bandbreite vor überhaupt nichts.
Die ehrliche Obergrenze für einen einzelnen Server ist ungefähr die kleinere von zwei Zahlen: die Portgeschwindigkeit, mit der er verbunden ist, und die Pakete pro Sekunde, die seine CPU klassifizieren kann. Ein 1-Gbps-Port ist bei 1 Gbps voll, ganz gleich, wie elegant Ihr Regelwerk ist, und eine moderate Flut kleiner Pakete kann ein paar Kerne mit der Interrupt-Verarbeitung auslasten, lange bevor die Bandbreitenzahl alarmierend aussieht. Jenseits dieses Punkts hilft nur noch ein Gerät weiter stromaufwärts, das mehr Kapazität hat als der Angriff und den Traffic verwirft, bevor er überhaupt Ihre Leitung erreicht. Genau das ist Scrubbing, und deshalb steht jede Maschine unserer Flotte hinter 1.5 Tbps durchgehend aktiver Mitigation statt hinter einer größeren Firewall.
Ebenso wichtig ist die Konsequenz daraus: Haben Sie keinen Upstream-Schutz, besteht die Antwort Ihres Providers auf einen großen volumetrischen Angriff darin, Ihre Adresse per Null-Route stillzulegen, weil die Alternative wäre, jeden anderen Kunden auf dieser Leitung zu beeinträchtigen. Das ist keine Böswilligkeit, das ist Arithmetik — und es bedeutet, dass der Angreifer gewinnt, indem er Sie teuer macht, statt etwas kaputtzumachen. Im Voraus zu wissen, ob Mitigation in Ihrem Plan enthalten ist oder ein kostenpflichtiges Extra, das Sie nie aktiviert haben, ist eine Fünf-Minuten-Prüfung, die sich heute lohnt und nicht erst während des Vorfalls. Unsere ist bei jedem Plan inklusive, und das ist die einzige Regelung, die um 3 Uhr morgens hilft.
SP·04Layer 7: die Flut, die aussieht wie Traffic
Eine Layer-7-Flut ist schwieriger, weil jede einzelne Anfrage legitim ist. Eine gut gebaute HTTP-Flut vervollständigt den TCP-Handshake, handelt TLS aus, schickt ein gültiges GET / mit einem plausiblen User-Agent und liest die Antwort. Kein einziges Paket darin ist fehlerhaft. Was Sie umbringt, ist die Arithmetik: Eine Anfrage kostet den Angreifer fast nichts zu senden und kostet Sie eine Datenbankabfrage, ein Template-Rendering und hundert Millisekunden eines Workers, der jetzt niemand anderen mehr bedient.
Die Anzeichen stehen in Ihrem eigenen Access-Log, und sie sind meist offensichtlich, sobald Sie gezielt danach suchen, statt nur draufzuschauen. Cache-Busting-Query-Strings — Tausende Anfragen an /?1234567, jede eine einzigartige URL, die jeden Cache aushebelt, den Sie besitzen — sind mit Abstand die häufigste Signatur. Eine User-Agent-Verteilung ohne Long Tail: echter Traffic ist eine unordentliche Mischung aus Hunderten Browser-Builds, und eine Flut besteht oft aus drei Zeichenketten, die eine Million Mal wiederholt werden, oder einer, die kein echter Mensch benutzt. Ein Referrer-Feld, das überall identisch ist. Anfragen, die Ihre statischen Assets komplett auslassen — ein echter Browser lädt nach dem HTML noch das CSS, die Schriften und die Bilder nach; ein Flut-Client fragt das HTML ab und verschwindet. Und eine Quellverteilung, die zu flach ist: Ein Botnet, verteilt über zehntausend Adressen aus Privathaushalten, von denen jede zwei Anfragen pro Sekunde sendet, sieht wie Popularität aus, bis Ihnen auffällt, dass die Rate pro Adresse verdächtig gleichmäßig ist.
Dann gibt es noch die Variante, die fast gar keinen Traffic braucht: den langsamen Angriff. Ein paar Hundert Verbindungen, die sich öffnen, alle zwanzig Sekunden einen Header senden und nie fertig werden, belegen jeden Worker, den Sie haben, während Ihr Bandbreiten-Graph flach bleibt. Die Lösung ist kein Rate Limit — die Anfragerate ist winzig —, sondern aggressive Header- und Body-Timeouts, weshalb sie weiter unten im ersten Konfigurationsblock auftauchen und nicht als nachträglicher Einfall.
SP·05Vier Kontrollen, geordnet nach Wirkung pro Minute
Tun Sie unter Druck zuerst das, was am meisten bewirkt. Die folgende Reihenfolge ist nicht willkürlich; sie ist grob absteigend danach sortiert, wie viel Last jede Maßnahme pro Minute Ihrer Aufmerksamkeit abwirft.
- Liefern Sie etwas Billiges aus. Ein Micro-Cache von dreißig Sekunden vor Ihrer Anwendung verwandelt tausend identische Anfragen pro Sekunde in einen Zugriff auf den Origin und 999 Lesevorgänge aus dem Speicher. Das ist der mit Abstand größte Hebel gegen fast jede HTTP-Flut, es kostet einen einzigen Block mit einer Direktive, und für anonymen Traffic ist es fast immer sicher. Fügen Sie
proxy_cache_lockhinzu, damit ein Cache-Miss keine Thundering Herd auf das Backend loslässt. - Nebenläufigkeit begrenzen und Timeouts verkürzen.
limit_connpro Adresse plus knappe Header-, Body- und Keepalive-Timeouts tötet langsame Angriffe direkt ab und verhindert, dass ein einzelner Client Ihren Worker-Pool blockiert. Das ist die Kontrolle, die echte Nutzer am wenigsten kostet. - Rate begrenzen, mit Burst.
limit_reqmit einem sinnvollen Burst ist präzise, aber langsamer zu justieren, und es ist die Maßnahme, die False Positives erzeugt, wenn Sie sie aus Panik statt aus Ihrer eigenen Baseline heraus einstellen. Sie müssen Ihre normale Anfragerate pro Sekunde und Client kennen, bevor Sie eine Zahl festlegen können — weshalb das Post-Mortem am Ende dieses Guides wichtiger ist, als es klingt. - Blockieren, eng begrenzt und zurückhaltend. Bestimmte Netze zu verwerfen funktioniert, wenn die Quellen konzentriert sind, und bringt nichts, wenn nicht. Es altert außerdem schlecht: Jede Blockade, die Sie während eines Vorfalls hinzufügen, ist womöglich ein Kunde, den Sie in drei Monaten stillschweigend abweisen. Verwenden Sie ein Set mit Timeout, damit die Regeln von selbst auslaufen.
Beachten Sie, was nicht auf der Liste steht: einzelne IP-Adressen von Hand sperren, den Webserver wiederholt neu starten, und die Firewall deaktivieren, um zu sehen, „ob das hilft“. Ersteres ist gegen eine verteilte Quelle zu langsam, um etwas zu bewirken, Zweiteres wirft jede warme Verbindung weg, die Sie hatten, und Drittens ist der Weg, wie aus einem Vorfall eine Kompromittierung wird.
SP·06Kämpfen Sie nicht von der Maschine aus, die Ihre Daten hält
Jede Kontrolle von oben ist mehr wert, wenn sie woanders läuft als auf der Box, die Ihre Datenbank hält. Ist Ihr Edge ein separater Knoten, endet die Flut auf einer Maschine, deren einzige Aufgabe es ist, Fluten zu beenden: Sie cacht, drosselt und verwirft, mit der echten Client-Adresse in der Hand, und der Origin sieht immer nur den kleinen, gefilterten Rest über einen privaten Tunnel. Fällt der Edge aus, ersetzen Sie ihn in 15 min und verlieren nichts, weil nichts darauf liegt. Fällt der Origin aus, haben Sie einen Ausfall und eine Wiederherstellung.
Diese Trennung schließt außerdem den Bypass, der die meiste Mitigation zur Dekoration macht. Hat der Origin noch einen öffentlichen Listener, kann ein Angreifer, der seine Adresse findet — über Passive-DNS, einen Certificate-Transparency-Eintrag, einen MX-Eintrag oder eine Link-Vorschau —, an jeder Kontrolle vorbeizielen, die Sie konfiguriert haben, und die Anwendung direkt treffen. Das kommt so häufig vor, dass man es bis zum Beweis des Gegenteils als Normalzustand jeder „geschützten“ Seite behandeln sollte. Die Version zu bauen, die hält, ist ein eigener Guide: ein Offshore-Reverse-Proxy ganz ohne öffentlichen Listener auf dem Origin.
Eine Warnung zur Mitte eines Vorfalls: Das ist Architektur, keine Erste Hilfe. Einen Edge aufzusetzen, DNS umzuziehen und einen Tunnel unter laufendem Angriff neu aufzubauen, ist ein Zwei-Stunden-Job, der unter Druck schlecht gemacht wird, und allein die DNS-Änderung greift erst nach Ablauf Ihrer TTL. Wenn Sie es haben, nutzen Sie es. Wenn nicht, kommen Sie mit den Kontrollen, die Sie haben, durch die Stunde, und bauen Sie es in der ruhigen Woche danach auf — genau dann, wenn es niemand tut.
SP·07Der Tag, an dem Sie der Reflektor sind, nicht das Ziel
Es gibt eine zweite Version dieses Vorfalls, bei der Ihr Server nicht das Opfer ist und niemand es Ihnen sagt. Ein offener Resolver, ein exponierter NTP-Daemon, ein unauthentifiziertes Memcached auf einer öffentlichen Schnittstelle, ein SSDP- oder CLDAP-Responder in einem Container — jeder davon beantwortet eine kleine gefälschte Anfrage mit einer viel größeren Antwort, gerichtet an jemand anderen. Von Ihrer Seite aus sind die Symptome umgekehrt: Die ausgehende Bandbreite ist hoch, die eingehende gering, Ihre Anwendung läuft einwandfrei, und das erste echte Signal ist eine Abuse-Meldung oder ein gesperrter Port.
Die Prüfung dauert eine Minute und gehört ins selbe Runbook, denn es ist derselbe Befehl, den Sie schon während der Triage ausgeführt haben. ss -tulpn sollte nichts auflisten, was an eine öffentliche Adresse gebunden ist, die Sie nicht absichtlich dorthin gelegt haben, und UDP-Dienste verdienen besonderes Misstrauen, weil sie diejenigen sind, die verstärken. Ein rekursiver Resolver muss an localhost oder an eine Tunnel-Adresse gebunden sein; Memcached und Redis dürfen niemals aus dem Internet erreichbar sein; und jeder Container, der einen Port mit -p 0.0.0.0: veröffentlicht, hat gerade ein Loch in die Firewall gerissen, die Sie konfiguriert haben, weil Docker seine eigenen Regeln vor Ihre schreibt. Genau das Letzte überrascht die Leute jedes einzelne Mal.
Dasselbe Muster deckt auch ausgehende Fluten von einer bereits kompromittierten Maschine ab, was der andere Grund ist, aus dem ein Provider eine Adresse plötzlich per Null-Route stilllegt. Ist Ihr ausgehender Graph hoch und Ihre Anwendung untätig, hören Sie auf, Konfigurationen zu lesen, und fangen Sie an, Prozesse zu prüfen — das ist ein Einbruch, kein Kapazitätsproblem, und die richtige Reaktion ist, die Box aus einem bekanntermaßen sauberen Backup neu aufzubauen, statt sie zu filtern.
SP·08Danach: das Post-Mortem und die Grundausstattung
Angriffe hören auf. Meist wird dem Angreifer langweilig, manchmal macht die Mitigation es sinnlos, gelegentlich war es ein befristetes Booter-Abo, das schlicht ausgelaufen ist. Die Versuchung in diesem Moment ist, alles genau so zu lassen, wie es ist, und ins Bett zu gehen — und genau so wird aus einem vorübergehenden Rate Limit neun Monate später ein dauerhaftes, vergessenes, stilles 429 für ein ganzes Land. Nehmen Sie sich zwanzig Minuten, um die Sache abzuschließen, solange sie noch frisch ist.
Drei Artefakte lohnt es sich zu erstellen. Eine Baseline: Ihre normale Anfragerate pro Sekunde, Ihre normale Rate pro Client, Ihre normale Bandbreite bei Spitzenlast. Ohne diese Zahlen ist jedes Limit, das Sie beim nächsten Vorfall setzen, eine Schätzung, und die Hälfte davon wird in die Richtung falsch liegen, die Kunden schadet. Eine Rollback-Liste: alles, was Sie geändert haben, mit Datum und Grund, damit die Notfallkonfiguration nicht stillschweigend zur dauerhaften wird. Ein Runbook, das vier Befehle lang ist und irgendwo liegt, wo Sie es erreichen, wenn die Seite down ist — nicht auf dem Server, und nicht nur im eigenen Kopf.
Schließen Sie dann die beiden strukturellen Lücken, denn genau hier sitzt diese Schicht im Stack. Mitigation absorbiert das Volumen, ein Edge hält die Flut von Ihren Daten fern, und die Box dahinter muss trotzdem richtig gehärtet sein und wiederherstellbare Off-Site-Backups haben, denn der nächste Vorfall nach diesem ist vielleicht gar keine Flut. Ein Server, der einen DDoS übersteht und einen Monat später seine Festplatte verliert, war nie widerstandsfähig — er hatte zweimal Glück.
SP·09Schritt für Schritt
-
01
Den Angriff bestätigen, bevor Sie etwas ändern
Verschaffen Sie sich ein ehrliches Bild der Maschine, bevor Sie eine Konfigurationsdatei anfassen. Sie suchen nach einer sprunghaften Veränderung bei Paketen oder Anfragen und danach, wohin die Zeit fließt — eine Anwendung, der Soft-Interrupts die CPU rauben, ist ein ganz anderer Vorfall als eine Anwendung, die auf eine Datenbank wartet.
# is the box alive, and where is the time going? uptime # load average against your core count vmstat 1 5 # 'in' and 'cs' high, 'id' near zero = packet work mpstat -P ALL 1 3 # %soft pinned on one core = interrupt saturation # is the pipe full, or just busy? ip -s link show eth0 # rx bytes, and the errors/dropped counters ethtool eth0 | grep -i speed # requests per second from your own log, minute by minute tail -n 20000 /var/log/nginx/access.log \ | awk -F'[][]' '{print $2}' | cut -d: -f2-4 | uniq -c | tail -5Bevor Sie es als Angriff einstufen, prüfen Sie Ihr eigenes Deploy-Log und Ihre Cron-Tabelle. Selbstverschuldete Ausfälle sind auf einem einzelnen VPS häufiger als Fluten, und von außen sehen sie gleich aus.
-
02
Die Form des Traffics in sechzig Sekunden messen
Jetzt klassifizieren Sie sie. Drei Fragen: wie viele verschiedene Quellen, welches Protokoll und welcher Zustand, und — falls es HTTP ist — welche Pfade und welche Agents. Die Antworten entscheiden, zu welcher Kontrolle Sie greifen, und sie zu sammeln dauert etwa eine Minute.
# top source addresses on the wire right now timeout 20 tcpdump -nn -i eth0 -c 20000 2>/dev/null \ | awk '{print $3}' | rev | cut -d. -f2- | rev \ | sort | uniq -c | sort -rn | head -20 # TCP state census: a wall of SYN-RECV is a SYN flood ss -tan | awk '{print $1}' | sort | uniq -c | sort -rn # layer 7: talkers, paths, agents over the last 50k requests L=/var/log/nginx/access.log tail -n 50000 $L | awk '{print $1}' | sort | uniq -c | sort -rn | head -20 tail -n 50000 $L | awk '{print $7}' | sort | uniq -c | sort -rn | head -20 tail -n 50000 $L | cut -d'"' -f6 | sort | uniq -c | sort -rn | head -10Lesen Sie das Ergebnis anhand der Anzeichen: einzigartige Query-Strings auf einem Pfad, eine User-Agent-Liste ohne Long Tail, keine Anfragen nach Ihren statischen Assets, oder eine Rate pro Adresse, die seltsam gleichmäßig ist. Ist die Bandbreite hoch auf Ports, auf denen Sie nicht lauschen, hören Sie hier auf — das ist eine volumetrische Flut, und Schritt sechs ist der einzige Schritt, der zählt.
-
03
Etwas Billiges ausliefern und die Verbindungen begrenzen
Zuerst das mit der größten Wirkung. Ein Dreißig-Sekunden-Micro-Cache verdichtet eine Flut identischer anonymer Anfragen zu einem einzigen Zugriff auf den Origin, und knappe Timeouts töten langsame Angriffe ab, die ein Rate Limit nicht sieht. Packen Sie beides in den
http-Block, und laden Sie dann neu, statt neu zu starten, damit Ihre warmen Verbindungen erhalten bleiben.# /etc/nginx/nginx.conf — http block limit_conn_zone $binary_remote_addr zone=perip:10m; limit_req_zone $binary_remote_addr zone=flood:20m rate=10r/s; client_header_timeout 10s; client_body_timeout 10s; send_timeout 10s; keepalive_timeout 20s; reset_timedout_connection on; proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=hot:64m max_size=2g inactive=10m use_temp_path=off;# the server block — cap concurrency, serve the cached copy limit_conn perip 20; location / { proxy_cache hot; proxy_cache_valid 200 301 302 30s; proxy_cache_lock on; proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504; add_header X-Cache $upstream_cache_status; proxy_pass http://127.0.0.1:8080; }nginx -t && systemctl reload nginx curl -sI https://example.com/ | grep -i x-cache # want: HIT on the second call
-
04
Die Rate des echten Clients begrenzen, nicht die des eigenen Proxys
Sitzt irgendetwas vor nginx, kommt jede Anfrage von einer einzigen Adresse, und ein Limit pro Adresse drosselt den Proxy statt den Angreifer — oder bannt ihn komplett und legt die Seite lahm, während Sie sie eigentlich verteidigen. Vertrauen Sie dem Forwarded-Header nur von der Proxy-Adresse, niemals aus dem Internet, und wenden Sie dann das Limit an.
# /etc/nginx/conf.d/realip.conf — the tunnel or edge address only set_real_ip_from 10.66.0.1; real_ip_header X-Forwarded-For; real_ip_recursive off;
# burst absorbs bursty humans; nodelay keeps the page fast for them location / { limit_req zone=flood burst=20 nodelay; limit_req_status 429; } # the expensive paths get a much tighter bucket of their own location ~ ^/(search|login|register|api/) { limit_req zone=flood burst=5; limit_req_status 429; }Beobachten Sie dann, was Sie gerade getan haben:
tail -f /var/log/nginx/error.log | grep limiting. Sehen die limitierten Adressen wie Ihre Kunden aus, ist die Rate zu niedrig — erhöhen Sie sie. Ein Limit, das echte Nutzer blockiert, ist ein Ausfall, den Sie sich selbst eingebrockt haben. -
05
Eng begrenzt blockieren und jeder Blockade ein Ablaufdatum geben
Nur sinnvoll, wenn Schritt zwei konzentrierte Quellen gezeigt hat. Verwenden Sie ein Set, keine tausend Regeln — ein
ipset-Lookup läuft in konstanter Zeit, eine langeiptables-Chain wird für jedes Paket durchlaufen und wird selbst zur eigenen Denial-of-Service. Geben Sie jedem Eintrag ein Timeout, damit aus dem Notfall von heute nicht die stille Sperrliste von nächstem Jahr wird.ipset create flood hash:net timeout 3600 -exist iptables -I INPUT -m set --match-set flood src -j DROP # feed it from the census: /24s you actually verified, not guesses for n in 203.0.113.0/24 198.51.100.0/24; do ipset add flood $n -exist; done # SYN flood: let the kernel do the part it is good at sysctl -w net.ipv4.tcp_syncookies=1 sysctl -w net.ipv4.tcp_max_syn_backlog=8192 sysctl -w net.core.somaxconn=8192 ipset list flood | head -20 # keep a copy of this for the post-mortem
Widerstehen Sie der Versuchung, per Geoblocking ein ganzes Land zu sperren, außer Sie können die Kunden benennen, die Sie damit aussperren. Und niemals
ufw disable, um eine Theorie zu testen: Eine ungeschützte Box unter aktivem Angriff ist der Weg, wie aus einem Bandbreiten-Vorfall ein Einbruch wird. -
06
Auf die Ebene eskalieren, die es tatsächlich abfangen kann
Sagen die Interface-Counter, dass die Leitung gesättigt ist, oder steigen die Drops, während Ihre CPU im Leerlauf ist, haben Sie die Obergrenze dessen erreicht, was sich auf dem Server tun lässt. Bestätigen Sie diesen Befund, und eskalieren Sie, statt weiter zu justieren.
# drops in the stack itself — second column is 'dropped' awk '{print strtonum("0x" $2)}' /proc/net/softnet_stat | paste -sd+ | bc # interface-level loss against link speed ip -s link show eth0 | sed -n '3,6p'Mit Upstream-Scrubbing im Einsatz gibt es meist nichts mehr zu tun: Die Erkennung läuft durchgehend, und die Flut wird im Netzwerk verworfen, bevor sie Ihren Port erreicht — auf unserer Flotte sind das 1.5 Tbps Kapazität, die vor jedem Plan liegen, sodass der Vorfall im Nachhinein oft nur noch als Graph sichtbar ist. Ist der Angriff eine wohlgeformte HTTP-Flut statt einer volumetrischen, ist das der Fall für ein L7-Schild, denn Anfragenfluten sind auf Paketebene nicht von echten Nutzern zu unterscheiden und müssen weiter oben beurteilt werden. Haben Sie überhaupt keine Mitigation, sind Ihre realistischen Optionen, hinter einen Edge zu ziehen, der das hat, oder zu warten — und Ersteres zu planen, bevor der nächste Angriff kommt.
-
07
Den Kreis schließen: verifizieren, zurückbauen, dann aufschreiben
Verifizieren Sie von außerhalb der Maschine, nicht aus einer Shell auf ihr. Machen Sie dann die Notfallmaßnahmen gezielt rückgängig, behalten Sie die, die schon immer eine gute Idee waren, und halten Sie die Zahlen fest, damit der nächste Vorfall von einer Baseline aus startet statt von einer Schätzung.
# from somewhere else entirely: is the site healthy for a normal user? curl -s -o /dev/null -w 'code=%{http_code} ttfb=%{time_starttransfer}s\n' \ https://example.com/ # did you leave a limit that is biting real people? grep -c 'limiting requests' /var/log/nginx/error.log # what is still blocked, and when does it expire? ipset list flood | head -30Behalten Sie den Cache, die Timeouts und die Syncookies — das sind dauerhafte Verbesserungen. Setzen Sie die aggressiven Rate Limits auf Ihre gemessene Baseline plus Puffer zurück, und lassen Sie die ipset-Einträge auslaufen. Schreiben Sie dann die vier Befehle aus den Schritten eins und zwei in ein Runbook, das nicht auf diesem Server liegt, direkt neben Ihrer normalen Anfragerate pro Sekunde und Ihrer normalen Spitzenbandbreite. Der nächste Angriff wird allein deshalb ein kürzerer Vorfall, weil diese beiden Zahlen existieren.


