Wie kann man die Rate in Nginx begrenzen, aber bestimmte IP-Adressen ein- / ausschließen?

27

Ich kann limit_reqalle Anfragen an meinen Server mit einer Ratenbeschränkung versehen.

Ich möchte jedoch die Ratenbeschränkung für bestimmte IP-Adressen (z. B. Whitelist) aufheben und für bestimmte andere (z. B. bestimmte IP-Adressen, die nur 1 r / s betragen sollen) eine andere Ratenbeschränkung verwenden.

Ich habe versucht, Bedingungen zu verwenden (z. B. if ( $remote_addr = "1.2.3.4" ) {}), aber das scheint nur mit Umschreiberegeln zu funktionieren, nicht für Ratenbegrenzungsregeln.

Jason Cohen
quelle

Antworten:

33

Es ist wirklich besser, die Verwendung der "if" -Direktive zu vermeiden. Wenn der Schlüssel in limit_req_zone (und limit_conn_zone) leer ist, werden die Grenzwerte nicht angewendet. Sie können dies in Verbindung mit den Karten- und Geomodulen verwenden, um eine Whitelist mit IPs zu erstellen, bei denen die Gasgrenzwerte nicht angewendet werden.

In diesem Beispiel wird gezeigt, wie Sie ein Limit sowohl für gleichzeitige Anforderungen als auch für die Anforderungsrate von einer einzelnen IP konfigurieren.

http {
    geo $whitelist {
       default 0;
       # CIDR in the list below are not limited
       1.2.3.0/24 1;
       9.10.11.12/32 1;
       127.0.0.1/32 1;
    }

    map $whitelist $limit {
        0     $binary_remote_addr;
        1     "";
    }

    # The directives below limit concurrent connections from a 
    # non-whitelisted IP address to five

    limit_conn_zone      $limit    zone=connlimit:10m;

    limit_conn           connlimit 5;
    limit_conn_log_level warn;   # logging level when threshold exceeded
    limit_conn_status    503;    # the error code to return

    # The code below limits the number requests from a non-whitelisted IP
    # to one every two seconds with up to 3 requests per IP delayed 
    # until the average time between responses reaches the threshold. 
    # Further requests over and above this limit will result 
    # in an immediate 503 error.

    limit_req_zone       $limit   zone=one:10m  rate=30r/m;

    limit_req            zone=one burst=3;
    limit_req_log_level  warn;
    limit_req_status     503;

Die Zonenanweisungen müssen auf der http-Ebene platziert werden, die anderen Anweisungen können jedoch weiter unten platziert werden, z. B. auf dem Server oder auf der Standortebene, um deren Umfang einzuschränken oder die Grenzen weiter anzupassen.

Weitere Informationen finden Sie in der Nginx-Dokumentation ngx_http_limit_req_module und ngx_http_limit_conn_module

Shonky Linux Benutzer
quelle
Was ist der Unterschied zwischen diesen beiden Modulen?
mente
1
Gemäß
Können Sie erklären, warum Sie das Mapping in zwei Schritten durchführen, geogefolgt von map, anstatt es nur geozum $limitdirekten Einstellen zu verwenden ?
Marcus Downing
2
Es scheint, dass geoes keiner Variablen zugeordnet werden kann. Wenn Sie also $binary_remote_addreinen Zuordnungswert angeben, wird dies in die Literalzeichenfolge übersetzt "$binary_remote_addr", nicht in den Wert der Variablen.
ColinM
1
Ich möchte hinzufügen, dass, wenn die fragliche IP bereits in der Zone ist, Sie nginx neu starten müssen ; ein nachladen reicht nicht aus.
Halfgaar
5

Sie können problemlos benannte Speicherorte verwenden, z. B. "@Location" in einem if () - Block.

Siehe: http://wiki.nginx.org/IfIsEvil

So etwas sollte funktionieren:

http {

   limit_req_zone $binary_remote_addr zone=delay:10m rate=1r/m;

   server {
      ...

      error_page 410 = @slowdown;

      if( $remote_addr != "1.2.3.4" ) {
         return 410;
      }

      location @slowdown {
         limit_req zone=delay burst 5;
         ...
      }

      location / {
         ...
      }
   }

Geben Sie "location @slowdown {}" mit den gleichen Informationen wie "location / {}" ein, z. B. "proxy_pass", wenn Sie "nginx" als Reverse-Proxy verwenden.

Robert Suh
quelle
Ich bin nicht sicher, ob ich den 410 Teil verstehe? Wird dem Client tatsächlich ein http 410-Statuscode angezeigt?
Svrist
1
Wow, das funktioniert tatsächlich! Sehr geschickter error_pageTrick, +1! @svrist, unter serverfault.com/a/870170/110020 finden Sie eine vollständige Erklärung, wie und warum so etwas funktionieren würde.
24.