WAFでIPごとではなくすべてのIPでレートベース制限を掛けられるか

目的・やりたいこと

WAFのレートベースルールとカスタムレスポンスで指定したページに一定のアクセス(コネクション)に達した際に、Sorryページなどには誘導できそうだが、ユーザ個別になるか全体で掛けられるかもう少し確認が必要
ということで、まずは情報がないか調査してみました。

AWSドキュメントAggregation options and keysでは、Count allを使えば全体で掛けられそうではある。

Count all – Count and rate limit all requests that match the rule's scope-down statement. This option requires a scope-down statement. This is typically used to rate limit a specific set of requests, such as all requests with a specific label or all requests from a specific geographic area.

訳すと、
「すべてカウント – ルールのスコープダウンステートメントに一致するすべてのリクエストをカウントし、レート制限します。 このオプションにはスコープダウンステートメントが必要です。 これは通常、特定のラベルを持つすべてのリクエストや特定の地理的領域からのすべてのリクエストなど、特定のリクエストのセットをレート制限するために使用されます。」
何のこっちゃわからない

Customize requests and responses with AWS WAFによると、「使用例 2: カスタム エラー ページ」より、以下の記載がある。

  1. AWS WAF には、5 分ごとに 100 件のリクエストを許可するレートベースのルールがあります。
  2. ユーザーが複数のリクエストを送信し、AWS WAF レートベースのルールのしきい値に違反しました。
  3. AWS WAF はユーザーからのそれ以上のリクエストをブロックします。
  4. AWS WAF カスタム レスポンス コード機能は、レスポンス コードをHTTP 307 – Temporary Redirectに変更し、 「リクエストが多すぎます」というメッセージを含むカスタム エラー ページで応答します。

この「ユーザー」というのが特定のユーザーなのか、ユーザー全体を指しているのかいまいち曖昧
ということで、やはり検証するのが早いということで検証することにしました!

対象となる技術

  • WAF
  • CloudFront

条件(導入にあたって前提事項)

  • 本検証はアクセス回数が重要であるため、キャッシュなどを含むことによる不正確なカウントになるなど余計な懸念を払拭するため、念のためCloudFrontでキャッシュしないようにしておく。 

参考URL

作業の流れ

概要図

インターネット---WAF---CloudFront---Web

事前作業

WAFでWeb ACLを作成します。
1.AWS WAF > Web ACLs で[Create web ACL]
2.AWSリソースはCloudFrontを選択

3.[Add rules] > [Add my own rules and rule groups]
4.[Rule builder]でTypeは[Rate-based rule]を選択
5.[Request aggregation]は最初は[Source IP address]を選択

6.Actionはこんな感じに

7.カスタムレスポンスボディはSorryページ風に

8.Web ACL作成
これで準備完了

検証手順

1.最初の5分間は以下のコマンドを実行して同じIPで100回アクセス

for i in {1..100}; do curl -s -o /dev/null -w "%{http_code}\n" https://d1z2cjnyfhe194.cloudfront.net/; done

2.120回目でレスポンスコード「307」が返ってくることを確認

200
200
200
200
200
200
200
200
200
200
307
307
307
307
307
307
307
307
307
307

なぜ100回ではなく120回目なのか腑に落ちないが、誤差も含めて約100回としておく

3.念のためブラウザでもSorryページを確認

4.次の5分間は、IPを変えて100回ずつアクセス

  • IP:106.154.144.14で試行
 % for i in {1..100}; do curl -s -o /dev/null -w "%{http_code}\n" https://d1z2cjnyfhe194.cloudfront.net/; done
 200
 〜略〜
 200
  • VPNに繋いで別のIP:134.238.x.xで試行
% for i in {1..100}; do curl -s -o /dev/null -w "%{http_code}\n" https://d1z2cjnyfhe194.cloudfront.net/; done
 200
 〜略〜
 200

5.この結果、トータルではなくIPごとにレート制限をカウントしていることがわかった

・ここでWeb ACLのルールを、[Source IP address]ではなく[Count all]に変更

6.次の5分間は、IPを変えて100回ずつアクセス

  • IP:106.154.144.14で試行
% for i in {1..100}; do curl -s -o /dev/null -w "%{http_code}\n" https://d1z2cjnyfhe194.cloudfront.net/index.html; done
 200
 〜略〜
 200
  • VPNに繋いで別のIP:134.238.x.xで試行
% for i in {1..100}; do curl -s -o /dev/null -w "%{http_code}\n" https://d1z2cjnyfhe194.cloudfront.net/; done
 200
 〜略〜
 200
307
307
307
307
307
307
307
307
307
307
307
307
307
307
307
307
307
307
307
307
307
307
307
307
307
307
307

IP:106.154.144.14は100回アクセス成功、一方の134.238.x.xは74回目で307に。つまりトータルで173回アクセスできたことになる。

所要時間

1時間

まとめ

IP [Source IP address] [Count all]
106.154.144.14 100 100
134.238.x.x 100 73

・[Source IP address]で制限した場合
⇨1つのIPで100回ずつアクセスできました。合計200回アクセス成功
・[Count all]で制限した場合
⇨1つ目のIPで100回アクセスできたものの、2つ目のIPは73回でSorryページにつながりました。

以上、想定より若干誤差はあるものの、[Count all]を使えばIPごとではなく、トータルでの制限が可能ということがわかりました!