DDos Mitigation

  • Heyho,


    während der Entwicklung einer API (auf WSC-Basis) wollte ich Rate-Limits implementieren und diese anschließend mittels ab (apache-utils) testen:


    Code
    ab -v 2 -n 100000 -c 55 "https://host"


    Dabei ist mir aufgefallen, dass es scheinbar problemlos möglich ist, einen Server zu DDosen und die Last auf 100% zu pushen. Nun scheint es allerdings auch so, dass ich mit diesem Problem nicht alleine bin. Xopez und Hanashi haben gestattet, dass ich die Auswirkungen auch auf deren Servern teste (bei Xopez ist sogar CF vorgeschaltet). Ergebnis:




    Tatsächlich habe ich mich bisher gar nicht so sehr damit auseinander gesetzt. Um so erschrockener bin ich über die Tatsache, dass so viele Server scheinbar nicht unbedingt zur Abwehr dieses doch sehr einfachen "Angriffs" konfiguriert sind.


    Auf unserem Server sind zwar etliche IPTables-Regeln und sysctl-Konfigurationen¹ zur Abwehr (oder zumindest zur Milderung der Auswirkungen) gewisser Attacken vorhanden und auch nginx ist gewissermaßen konfiguriert², aber trotz einer 429er Response werden zig PHP und MySQL-Prozesse gestartet und ich habe keinen blassen Schimmer, wie sich das effektiv verhindern lässt, ohne legitime Aufrufe ggf. zu blockieren.


    Hat sich schon einmal jemand intensiver damit auseinander gesetzt und ein paar Tipps?


    ¹ =


    ² =

  • Hi,


    Ich weiß aus eigenen Erfahrungen dass der Schutz von Cloudflare sogut wie gar nichts bringt wenn nicht gerade die Captcha Anfrage davor geschaltet ist, das wird in deinem Fall mit der API wohl nicht weiterhelfen.


    Edit. Aber vielleicht können die rate limits von cloudflare pro dir da gut weiterhelfen, kostet leider halt nur wieder geld 🙈


    Vielleicht kann dir ein Load balancer da mehr bringen da bei deinen Vorhaben eh wahrscheinlich viel Last auf dem Server entsteht durch die Bilderbearbeitung solltest das eh auf paar Server aufteilen weil wenn da viele Bearbeitungen zeitgleich reingehen gibs Chaos (meiner Meinung nach).


    Ps. DDoS kriegt man nur schwer in den Griff selbst cloudflare und die großen Systeme von den großen Hostern haben da Probleme und es wird oftmals nur der ganze Server gesperrt und Null-Routed 😬😬

    ┌П┐(◉_◉)┌П┐

  • Die Zeilen


    limit_conn conn_limit_per_ip 40;
    limit_req zone=req_limit_per_ip burst=40 nodelay;


    hast du aber schon in deinem location Block eingetragen ?


  • Ich kann das bei mir mal eben testen, aber ich hatte das schon immer im location Block drin.


    Edit: OK, es reicht wenn man die im Server-Block einträgt. Ich habe es bei mir auf 10r/s limitiert und mit ab getestet.


    • Official Post

    Überlebt der Server überhaupt 40r/s? Und warum nur 3 eine ungerade Anzahl an Hardware-Threads? Das ist in Punkto Sicherheit (Seitenkanal-Angriffe) als auch Performance (Cache-Thrashing) nicht unbedingt ideal.


    Deine Konfiguration sagt lediglich, dass jede Request über dem Limit einen 429 auslöst, die anderen gehen aber durch. Der Burst ist auch etwas merkwürdig, das verwendet man üblicherweise für kurze Spikes, 40r/s ist als Spike aber schon sehr sportlich, weshalb dies nicht wirklich einen Effekt hat.


    Ein Connection-Limit von 40 ist übrigens etwas irreführend, sobald du dich in HTTP/2-Territorium begibst. Mit Multiplexing kann dir eine einzige Connection den Server zunageln.

  • Überlebt der Server überhaupt 40r/s? Und warum nur 3 eine ungerade Anzahl an Hardware-Threads? Das ist in Punkto Sicherheit (Seitenkanal-Angriffe) als auch Performance (Cache-Trashing) nicht unbedingt ideal.


    Deine Konfiguration sagt lediglich, dass jede Request über dem Limit einen 429 auslöst, die anderen gehen aber durch. Der Burst ist auch etwas merkwürdig, das verwendet man üblicherweise für kurze Spikes, 40r/s ist als Spike aber schon sehr sportlich, weshalb dies nicht wirklich einen Effekt hat.


    Ein Connection-Limit von 40 ist übrigens etwas irreführend, sobald du dich in HTTP/2-Territorium begibst. Mit Multiplexing kann dir eine einzige Connection den Server zunageln.


    Ich experimentiere noch damit. Denn zu niedrige Werte haben stellenweise auch dazu geführt, dass einige Assets nicht geladen wurden, usw. Das ist, was ich damit meinte:


    ohne legitime Aufrufe ggf. zu blockieren.


    Auf der einen Seite will ich verhindern, dass mir ein simpler Aufruf von ab den ganzen Server lahmlegt, weil unaufhörlich neue PHP- und MySQL-Prozesse gestartet werden, auf der anderen Seite soll der normale Besucher davon nichts mitbekommen. Leider fische ich bei Ratelimits in nginx noch etwas im Trüben. Das ist leider eines der wenigen Themen, mit denen ich mich noch nicht wirklich auseinander gesetzt habe, weil das Problem für mich bisher gar nicht so präsent war.

    • Official Post

    […] weil unaufhörlich neue PHP- und MySQL-Prozesse gestartet werden

    Wie soll das gehen?


    Wie viele Threads MySQL hat, ergibt sich direkt aus der Konfiguration. Wie viele Threads PHP hat, hängt von der PHP-FPM-Konfiguration ab. Wie viele Threads nginx hat, hängt auch direkt von der Konfiguration ab.


    Das System hat laut htop 3 Hardware-Threads, wenn ich jetzt mutig bin und MySQL und nginx auf einen Hardware-Thread lege, dann habe ich noch 2 frei für PHP. Daraus lässt sich dann der optimale Wert errechnen und ab dann sind die Anzahl der Prozesse praktisch konstant.


    Mein Verdacht ist, dass du zu viele PHP-Worker laufen hast, die sich gegenseitig im Weg stehen, wodurch sich das Problem noch verschlimmert. Aber das lässt sich nur beantworten, wenn man sich im Detail anschaut, was für Prozesse laufen und womit die beschäftigt sind.


    […] die großen Systeme von den großen Hostern haben da Probleme und es wird oftmals nur der ganze Server gesperrt und Null-Routed

    You get what you pay for.

  • Ich möchte kurz anmerken, dass der Screenshot von oben von meinem Server stammt, nicht, dass es da zu Verwechslungen kommt.

    „If you can only do one thing, hone it to perfection. Hone it to the utmost limit!“ – Zenitsu Agatsuma

  • You get what you pay for.

    Hetzner, aber mir persönlich noch nicht passiert aber viel davon gehört ☺️ ich konnte Angriffe immer mit cloudflare captcha abwehren (solange die Back-end-IP nicht bekannt ist geht das auch sehr gut).


    Die Aussage war aber eher darauf bezogen dass die groß angekündigten D(d)os-Schutzmaßnahmen in der Regel wenig bringen.


    Nachtrag: Für firmen lohnen sich auch teure Systeme aber für Privat betriebene Systeme macht es wenig Sinn mehrere Hundert Euro zu investieren.

    ┌П┐(◉_◉)┌П┐

  • Und warum nur 3 eine ungerade Anzahl an Hardware-Threads? Das ist in Punkto Sicherheit (Seitenkanal-Angriffe) als auch Performance (Cache-Trashing) nicht unbedingt ideal.

    Darf ich dazu eine nähere Erläuterung oder Quelle erfahren?

    Ich bin nunmal in der Hetzner Cloud und dort werden auch 3 vCPU's angeboten:


    Der nächste in der CPX Reihe wäre:


    Die CPU Basis sind AMD EPYC 2nd Gen


    den ersten habe ich auf 3 Servern, da der mir eigentlich vollkommen reicht. Aus Perfomancesicht sehe ich keinen Grund ein höheres Produkt zu wählen.

    Deshalb wäre es toll, grade mehr zum Thema Side Channel zu erfahren sowie Cache-Trash.

    „If you can only do one thing, hone it to perfection. Hone it to the utmost limit!“ – Zenitsu Agatsuma

  • Mein Verdacht ist, dass du zu viele PHP-Worker laufen hast, die sich gegenseitig im Weg stehen, wodurch sich das Problem noch verschlimmert. Aber das lässt sich nur beantworten, wenn man sich im Detail anschaut, was für Prozesse laufen und womit die beschäftigt sind.


    In meinem Fall ist PHP für ondemand konfiguriert, nicht dynamic. Das könnte eine Erklärung dafür sein.


    Mir kam allerdings auch gerade die Erleuchtung, dass Rate-Limits auf Server-Basis meist gar nicht sinnvoll sind, weil ja dann auch z.B. statische Assets mit einbezogen werden. Daher auch die 40r/s. Tatsächlich dürften in einem Standard-WSC vermutlich 5 mehr als ausreichend sein, wenn man es nur auf PHP-Requests anwendet. Oder? Und dann halt nicht auf Server-Basis, sondern in der PHP-Route. Aber greift das dann auch bei internen Redirects aka SEO-Urls?

    • Official Post

    den ersten habe ich auf 3 Servern, da der mir eigentlich vollkommen reicht. Aus Perfomancesicht sehe ich keinen Grund ein höheres Produkt zu wählen.

    Deshalb wäre es toll, grade mehr zum Thema Side Channel zu erfahren sowie Cache-Trash.

    Bei virtuellen CPUs wie bspw. bei Hetzner hast du so oder so mit Overcommitment zu tun. Meine Aussage bezog sich auf Hardware-Threads im Falle von CPU-Passthrough, dort ist es aus den genannten Gründen üblich, Hardware-Threads als Vielfaches von 2 zu vermieten.


    Zu der Thematik der Side Channel Attacks bombardiert dich die Suchmaschine deiner Wahl mit Informationen, das ging die letzten Jahre gut durch die Presse. Cache-Thrashing (in meinem ursprünglichen Text fehlte das "h") bezeichnet das Problem, dass entsteht, wenn durch häufige Context- bzw. Process-Switches der CPU-Cache invalidated wird, wodurch die Daten im worst-case aus dem System-RAM jedes mal neu ausgelesen werden müssen. Bei ausreichenden CPU-Cores kann sich für so etwas auch ein CPU-Pinning anbieten, um Cache Misses deutlich zu reduzieren. Der Zugriff auf den System-RAM dauert aus CPU-Sicht eine halbe Ewigkeit. Aber auch dazu gibt es deutlich bessere Erklärungen zu der Thematik, falls es dich interessiert: "cpu cache hierarchy" ist ein guter Suchbegriff dafür.


    Tatsächlich dürften in einem Standard-WSC vermutlich 5 mehr als ausreichend sein, wenn man es nur auf PHP-Requests anwendet. Oder?

    Jaein. Attachments oder Galerie-Bilder sind so Kandidaten, bei denen es auch mal mehr Requests gibt. Aber genau dafür eigenet sich der Burst, etwa 5req/s und ein Burst von 40 würde also temporär eine Überschreitung zulassen. Einem Angreifer stünden somit effektiv nur die 5req/s zur Verfügung.

  • Jaein. Attachments oder Galerie-Bilder sind so Kandidaten, bei denen es auch mal mehr Requests gibt. Aber genau dafür eigenet sich der Burst, etwa 5req/s und ein Burst von 40 würde also temporär eine Überschreitung zulassen. Einem Angreifer stünden somit effektiv nur die 5req/s zur Verfügung.

    Habe ich eben probiert und klappt bei mir ohne Probleme. Die Auslastung ist nun nicht mehr auf 100%.


    Innerhalb von http { ... }:

    Code: nginx.conf
    limit_req_zone $binary_remote_addr zone=mylimit:10m rate=5r/s;

    Innerhalb von location { ... } im vhost:

    Code: vhost
    limit_req zone=mylimit burst=40;

    Mehr Infos dazu: https://www.nginx.com/blog/rate-limiting-nginx/


    Edit: wenn man Cloudflare nutzt, müsste man anstatt $binary_remote_addr, $http_cf_connecting_ip nutzen (Quelle: https://stackoverflow.com/ques…my-site/61735292#61735292).

Participate now!

Don’t have an account yet? Register yourself now and be a part of our community!