nginx - kleiner flood schutz

  • Ein freundliches Moin Moin in die Runde,


    ich bin gerade dabei auf meinem Server einen kleinen "floodschutz" einzurichten. Im Netz findet man dazu ja allerhand - zumindest in Verbindung mit nginx.


    Ich habe mich für folgende "Variante" entschieden:

    nginx.conf

    Code
    limit_req_zone $server_name$request_uri zone=limitzone1:5m rate=1000r/s;

    server.conf

    Code
    limit_req zone=limitzone1;


    Die limit_req_zone "$binary_remote_adress", wie es so oft vorgeschlagen wird, funktioniert bei mir nicht. Viele Wordpress Plugins funktionieren dann nicht mehr. Keine Ahnung warum.


    Meine aktuelle Lösung funktioniert aber auch nicht ganz ohne Fehler. Die Plugins laufen zwar soweit aber hier und da gibt es dann doch noch kleine Probleme (z.B. mit mainwp)


    Ich hoffe es gibt hier jemanden, der sich mit diesem Thema bereits auseinandergesetzt hat...

  • Erkläre doch mal was Du genau schützen willst. Denn je nach dem was Du da auf dem NGINX betreibst muss das Rate Limiting unterschiedlich konfiguriert werden. Dein aktuelles Setup besagt, dass jede URL maximal 1000 mal pro Sekunde aufgerufen werden kann. Nehme ich also 10 verschiedene URLs und spamme die fleißig, schaffe ich schon mal 10.000 Anfragen pro Sekunde.


    Hast Du ein PHP Backend, hab ich das damit normal schon kaputt gemacht.


    Es macht in den meisten Fällen Sinn, gleichzeitig noch Caching zu nutzen. NGINX selbst kann viel viel viel viel mehr Requests verarbeiten als irgendein (PHP?) Backend das könnte.


    Achtung! Es folgt schamlose Eigenwerbung:

    Siehe auch dazu einen Blog Post von mir: https://anysrc.net/post/gnu-linux/gehaertete-http-api-nginx

  • Ach mist,

    manchmal ist man einfach zu schnell mit dem Schreiben bevor mal alles geprüft hat.


    Der Error.log gab Aufschluss, dass das limit mehrmals erreicht wurde. Hätte zwar nicht gedacht, dass so extrem viele requests von mainwp bei einem Updatecheck aufgebaut werden...aber gut :)


    Limit erhöht und alles funktioniert wieder.


    Aber über 1000 requests pro Sekunde bei 6 zu prüfenden mainwp-child-seiten - krass xD

  • Danke für die schnelle Antwort.


    Das "Problem" ist mittlerweile ja gelöst. Der FastCGI-Cache läuft bei mir sowieso, ein wahres Wundermittel zu high-traffic Zeiten. :)


    Mir geht es nur darum, "Skript-Kiddies" den Spaß etwas zu vermiesen. xD Seit einiger Zeit habe ich nämlich größere Anfragen mit teils gleicher IP. Spielt vielleicht jemand mit kali-linux herum xD


    Die IPs über die limit_req_zone zu blocken hatte ich ja auch versucht aber da spielte Wordpress nicht mit.

  • Wenn Du das nicht mit IP machst sperrst Du halt nach erreichen des Limits alle User aus. Damit machst Du es den Kiddies noch viel viel leichter.

    Das stimmt, aber - Gott weiß warum - funktioniert es nicht. Habe es ganz normal mit:

    Code
    limit_req_zone $binary_remote_addr zone=limitzone1:5m rate=1000r/s;

    probiert. Und dann funktionierte bei Wordpress nichts mehr. Texte fehlten, Bilder wurden nicht mehr angezeigt....

  • OK, durch einen blöden Zufall herausgefunden:


    Wenn ich die zone durch "limit_req zone=limitzone1;" im Serverblock aktiviere, hat man ja eine "burst" Möglichkeit - sprich den kleinen Puffer.


    Dieser "Burst" hat anscheinend eine Art default Wert (habe ich noch nichtmal direkt in den docs bei nginx gelesen) wenn man ihn nicht setzt. Bei 1000r/s dachte ich... warum sollte man da noch einen setzen.


    Sprich den Burst=1000 gesetzt und es läuft - "limit_req zone=limitzone1 burst =1000;"


    ...Rechner aus, genug für heute xD

  • Ansonsten geht das auch über die Firewall und vermutlich auch zuverlässiger^^

    Code
    # Limit auf 100 Verbindungen pro IP, egal ob TCP/UDP und egal welcher Port
    # bestehende und neue Verbindungen werden gedroppt
    iptables -I INPUT -i eth0 -m connlimit --connlimit-above 100 -j DROP
    
    # Limit auf 100 Verbindungen pro IP, egal welcher Port (TCP only, da UDP verbindungslos)
    # bestehende Verbindungen funktionieren weiterhin, nur neue werden abgelehnt
    iptables -I INPUT -i eth0 -p tcp --syn -m connlimit --connlimit-above 100 -j DROP
    
    # Limit auf 20 Verbindungen pro IP mit TCP auf Port 80, nur neue Verbindungen werden gedroppt
    iptables -I INPUT -p tcp --syn --dport 80 -m connlimit --connlimit-above 20 -j DROP

    um 3 (ungetestete) Beispiele zu machen :)

  • Wäre da nicht Fail2Ban eine überlegung?

    Genau das habe ich bei meinem Beispiel probiert. Tut. Das. Nicht. Wenn der Spammer es ernst meint, verursacht der so einen hohen Traffic, dass fail2ban mit dem scannen der Logs nicht hinterher kommt. Das Filtern muss von NGINX selbst oder vom Kernel/Netzwerkstack (iptables) kommen.

  • Mit fail2ban habe ich nur meinen ssh Port "gesichert". Bis auf den, der eh geändert wurde - ist nur der 80 sowie 443 von außen erreichbar. Die ganze E-Mailgeschichte lasse ich über den Domainanbieter laufen, sodass auf meinem Server nur das reine Hosting läuft. Meine Wordpress-Seiten verschicken also über smtp ihre Mails.


    Ich habe es im laufe des Abends noch ausreichend getestet und seit der "burst-Sache" läuft alles wunderbar. Auch eigene Tests mit Kali-Linux verliefen gut - bisher alles safe.:thumbup:

  • Nur mit der eigenen IP muss man aufpassen... Ist immer wieder spaßig, wenn Putty aufeinmal timeoutet und man sich an den Kopf fasst, weil man ja von derselben IP eben erst getestet hat...

  • Moin Moin,


    ich muss mich zu diesem Thema doch noch einmal melden.

    Ich habe im http-Block einen Request von 50r/s eingestellt. In dem Server-Block noch einen burst=75 als "Puffer". Meine Seiten haben im Schnitt weniger als 10r (prüfung mit pingdom) pro Aufruf.


    Dennoch bekomme ich folgenden Fehlerlog:

    Code
    2018/05/05 02:29:39 [warn] 14280#14280: *41 delaying request, excess: 1.000, by zone "limit", client: 2.205.xxx.xxx, server: meinedomain.de, request: "GET /blablabla...


    Ich dachte erst, das die Zonen vielleicht voll sind aber auch ein Neustart von nginx brachte keinen Erfolg. An meiner Config hatte sich seit den letzten Tests nichts geändert. Lediglich nginx selbst wurde aktualisiert. Selbst bei einem eingestellten Request von 500r/s gab es einen Eintrag im Log.


    ...schon komisch :/

  • Und weil ich schonmal dabei bin: die limit_conn funktioniert gar nicht. Die ist so eingestellt, dass mehr als 20 gleichzeitige Verbindungen nicht zugelassen werden.


    getestet mit:

    Code
    ab -c 50 -n 10000 https://meinedomain.de/