web-dev-qa-db-ja.com

個々のURLリクエストのレート制限

私が開発しているFlaskアプリケーションは、外部Webサイトの操作に大きく依存しており、エンドユーザーによって開始されます。帯域幅の制御/レート制限を行わずにアプリケーションを終了すると、このアプリケーションは悪意のあるアクターによって悪用される可能性があります。

私の目標は、かなりシンプルな2段階のアプローチです。

  1. 個々のIPソースが1分間にxを超える接続を実行するのを制限するレート。これは、iptablesで簡単に実現できます。 これが私の目標に似た例です

     iptables -A INPUT -p tcp --syn --dport 80 -m connlimit --connlimit-above 15 \
       --connlimit-mask 32 -j REJECT --reject-with tcp-reset  
    
  2. URLごとにxを超えるルックアップを実行するアプリケーションの能力を制限します。例:

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

私が知る限り、iptablesには個別のURLを追跡する方法がありません。これらの接続全体のレート制限のみが可能です。それはまた、私が達成しようとしていることに対する唯一の制限のようにも思えません。この方法でiptablesをセットアップする方法があった場合、これらのリクエストはユーザーが開始するため、Webアプリケーションでいくつかの問題が発生する可能性があります。

Flaskを使用していますが、実行可能なオプションは before_request hook を使用し、Redisなどのデータストアでこれらの宛先を手動で追跡することです。ただし、この方法で接続を処理するために、これはスタック内でかなり高くなっています。私が本当に必要とする(または考える)のは、カスタムの方法で要求を分析し、特定のブレークポイントに到達したときに接続を閉じることができるインテリジェントなファイアウォールアプリケーションです。

私がやろうとしていることを達成する方法はありますか?

もしそうなら、どのように?

8
Ryan Foley

iptablesは、インターネット層とトランスポート層(インターネットモデル)またはOSIモデルの層3と4を扱いますが、いくつかの例外があります(MACアドレスのフィルタリング、NATプロトコルヘルパー)。

URIはアプリケーション層の一部です。 iptablesはそれらを処理しません。

Iptablesを使用して、すべての発信TCPポート80トラフィックをWebプロキシ経由で転送できます。これにより、レート制限が可能になります(たとえば Squidの遅延プール が可能です。またはApacheおそらくmod_proxyで可能です。HTTPSでこれを行うのはより困難です(ただし、Webプロキシを使用するようにアプリを構成することができますが、いずれにしても透過プロキシよりも優れたアプローチです)。

しかし、実際には両方のレート制限をアプリケーションに移動する必要があります。設定しているUXの理由はひどい; 「接続が拒否されました」は、何が起こっているのかをまったく説明できません。 much代わりに、ユーザーが速すぎるリクエストを行っていることを説明するエラーページを表示し、サポートに連絡するか、CAPTCHAを解決して続行するためのオプションを提供すると、等.

着信接続に接続レート制限を設定することは合理的ですが、DoS攻撃(アプリがユーザーにレート超過エラーページを提供することさえできないほど多くのリクエスト)によるアプリの転倒を防ぐためです。エラーページの提供を開始するときよりもかなり高くする必要があります(ソースIPごとの制限ではなく、グローバルな制限にする必要があります)。アプリがWebサーバーやリバースプロキシを介して実行されている場合は、(iptables経由ではなく)着信レート制限を設定できます。静的エラーページを送信することでvery安価な拒否を行うことができます。 、リクエストをアプリに渡すことさえしません。

3
derobert