Ratenbegrenzung einzelner URL-Anfragen

8

Ich habe eine Flask-Anwendung, die ich entwickle und die stark von der Interaktion mit externen Websites abhängt und vom Endbenutzer initiiert wird. Wenn ich die Anwendung ohne irgendeine Art von Bandbreitenkontrolle / Ratenbegrenzung verlasse, kann diese Anwendung von Akteuren mit schändlichen Absichten missbraucht werden.

Mein Ziel ist ein ziemlich einfacher zweistufiger Ansatz:

  1. Ratenbegrenzung für einzelne IP-Quellen, die mehr als eine xAnzahl von Verbindungen pro Minute ausführen . Dies kann leicht mit erreicht werden iptables. Hier ist ein ähnliches Beispiel für mein Ziel:

     iptables -A INPUT -p tcp --syn --dport 80 -m connlimit --connlimit-above 15 \
       --connlimit-mask 32 -j REJECT --reject-with tcp-reset  
    
  2. Die Rate begrenzt die Fähigkeit der Anwendungen, mehr als die xAnzahl der Suchvorgänge pro URL durchzuführen . Beispiel:

     APP ---- 10 pps --->  stackexchange.com   PERMIT
     APP ---- 25 pps --->  google.com          DENY / 15 SECOND BACKOFF
    

Soweit ich das beurteilen kann, iptablesgibt es keine Möglichkeit, separate URLs zu verfolgen. Es ist nur möglich, diese Verbindungen als Ganzes zu bewerten. Das scheint auch nicht die einzige Einschränkung dessen zu sein, was ich erreichen möchte. Wenn es eine Möglichkeit zum Einrichten iptablesauf diese Weise gibt, kann dies zu Problemen mit meiner Webanwendung führen, da diese Anforderungen vom Benutzer initiiert werden.

Ich verwende Flask. Eine praktikable Option könnte darin bestehen, einen before_requestHook zu verwenden und diese Ziele manuell mit einem Datenspeicher wie Redis zu verfolgen. Dies ist jedoch ziemlich weit oben im Stapel, um Verbindungen auf diese Weise zu behandeln. Was ich wirklich brauche (oder glaube), ist eine intelligente Firewall-Anwendung, die Anforderungen auf benutzerdefinierte Weise zerlegen und Verbindungen schließen kann, wenn bestimmte Haltepunkte erreicht wurden.

Gibt es eine Möglichkeit, das zu erreichen, was ich versuche?

Wenn das so ist, wie?

Ryan Foley
quelle

Antworten:

3

iptables befasst sich mit den Internet- und Transportschichten (im Internetmodell) oder alternativ mit den Schichten 3 und 4 im OSI-Modell, mit wenigen Ausnahmen (Filtern nach MAC-Adressen, NAT-Protokoll-Helfer).

URIs sind Teil der Anwendungsschicht. iptablesgeht nicht mit ihnen um.

Sie könnten iptables verwenden, um Ihren gesamten ausgehenden TCP-Port 80-Verkehr über einen Webproxy zu leiten, was Ihre Ratenbegrenzung bewirken könnte (z. B. könnten Squids Verzögerungspools dies tun. Oder Apache kann mod_proxydies wahrscheinlich mit .) Dies mit HTTPS zu tun ist schwieriger ( Vielleicht können Sie Ihre App auch so konfigurieren, dass sie einen Web-Proxy verwendet. Dies wäre ohnehin ein besserer Ansatz als ein transparenter Proxy.

Aber Sie sollten wirklich beide Tariflimits in Ihre Anwendung verschieben. Der Grund dafür, dass Sie die UX einrichten, ist schrecklich . "Verbindung abgelehnt" kann überhaupt nicht erklären, was passiert. Es wäre viel besser für Ihre Benutzer, wenn Sie stattdessen eine Fehlerseite angeben würden, auf der erklärt wird, dass sie zu schnell Anfragen stellen, an wen sie sich wenden können, um Unterstützung zu erhalten, möglicherweise eine Option zum Lösen eines CAPTCHA angeben, um fortzufahren usw.

Es ist vernünftig, eine Verbindungsratenbeschränkung für eingehende Verbindungen festzulegen, aber es sollte sein, die App vor einem Umfallen aufgrund eines DoS-Angriffs zu schützen - so viele Anfragen, dass Ihre App dem Benutzer nicht einmal die Seite mit der Rate überschritten kann, auf der die Fehler überschritten wurden. Es sollte ein gutes Stück höher sein als zu Beginn der Bereitstellung der Fehlerseite (und sollte möglicherweise ein globales Limit sein, kein IP-Limit pro Quelle). Beachten Sie, dass Sie, wenn Ihre App über einen Webserver und / oder einen Reverse-Proxy ausgeführt wird, dort wahrscheinlich Grenzwerte für eingehende Raten konfigurieren können (anstatt über iptables) und sehr billige Ablehnungen durchführen können, indem Sie eine statische Fehlerseite senden und die Anforderung nicht einmal weiterleiten zu Ihrer App.

derobert
quelle