Cloudflare Rate Limiting Rules (Advanced Rate Limiting) の紹介

## はじめに

Cloudflare でオリジンサーバーを保護し、アプリケーションサービスの安定提供を目指すプロダクトの 1 つに [Rate Limiting Rules](https://developers.cloudflare.com/waf/rate-limiting-rules/) があります。

Eyeball から着信したリクエストを条件によってカウントし、しきい値を超えた場合は抑制し、オリジンサーバーへの過度なアクセスを防ぐ効果が期待できます。

### "Rate Limiting Rules" = "Advanced Rate Limiting"
本家ページで使われている用語が若干ややこしいので、プロダクトとその名前の解説を少し。

2022 年に Rate Limitng Rules が出てきたのですが、これは現在の Cloudflare Proxy を支えている [Ruleset Engine](https://developers.cloudflare.com/ruleset-engine/) の上に建つプロダクトの 1 つです。以前は別のエンジンを使う Rate Limitng がありました。

ダッシュボード上では新しい Rate Limiting Rules を [Advanced rate limiting](https://blog.cloudflare.com/advanced-rate-limiting/)、以前のものは [Previous version](https://developers.cloudflare.com/waf/reference/legacy/old-rate-limiting/) と区別しています。（API も違います）

#### Advanced
<img width="600" alt="Screenshot 2023-10-07 at 18.25.19.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2218045/ea52f831-d9d4-322a-65a0-bf60def04e73.png">

API は[こちら](https://developers.cloudflare.com/api/operations/listZoneRulesets)（Rulesets 共通のエンドポイント）。
Ruleset Engine の [phase](https://developers.cloudflare.com/ruleset-engine/about/phases/) は [http_ratelimit](https://developers.cloudflare.com/waf/rate-limiting-rules/create-api/) になります。

#### Previous 
<img width="600" alt="Screenshot 2023-10-07 at 18.25.04.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2218045/dc62f89b-cbb9-7182-68e0-4e3bc2718a7b.png">

API は[こちら](https://developers.cloudflare.com/api/operations/rate-limits-for-a-zone-list-rate-limits)。

## Rate Limiting Rules 動作イメージ

ざっくり書くと、レートリミットの候補となったリクエストは指定した条件によってクラス分けされます。そのクラスでリクエストのカウンターがしきい値を超過すると、後続のリクエストはレートリミットのアクションを取られます。

リクエストをレートリミット候補にするか、どういう場合にレートリミットをかけるか、どういう場合にカウンターを加算するか、これらの条件を別に指定できることが特徴の一つになります。

```mermaid
flowchart LR
    A[リクエスト] -->|着信| B[\入力マッチルール/]
    B --> C{リクエストの特徴で<br>クラス分け}
    C -->|クラス1| D{レートリミット中?}
    subgraph クラス1
    D -->|yes| F(アクション)
    D -->|no| G{カウント条件に合う?}
    G -->|yes| H[カウンター+1 & 通過]
    H -.レートリミットトリガー.->D
    G -->|no| I[通過]
    end
    C -->|クラス2| J{レートリミット中?}
    subgraph クラス2
    J -->|yes| K(アクション)
    J -->|no| L{カウント条件に合う?}
    L -->|yes| M[カウンター+1 & 通過]
    M -.レートリミットトリガー.->J
    L -->|no| N[通過]
    end
```

## 入力マッチルール（If incoming requests match...）
着信したリクエストをレートリミット候補にするかの条件定義です。
<img width="600" alt="Screenshot 2023-10-07 at 12.02.58.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2218045/fe0f038e-999d-fbca-484e-7911b16bffb0.png">

`(http.host eq "ec2.oyama.cf")`と指定してます。

この場合、host にマッチしたものがレートリミットの対象になります。
入力マッチに使える Field は[後述](#入力マッチに使える-expression-field)します。
また、`Cache status` をチェックすると、キャッシュ済みのアセットもレートリミットの対象とすることができます。

## 特徴でクラス分け（With the same characteristics...）
リクエストを区別しクラス分けすることで、レートリミットの適用範囲を限定します。
<img width="600" alt="Screenshot 2023-10-07 at 12.05.22.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2218045/ccf8a700-8ea2-6e4b-6e68-fe367c2439af.png">

この場合、送信元の IP アドレスごとにクラスを分けます。クラスごとにカウンター値が加算されます。

なお、Rate Limiting Rules は Cloudflare の[データーセンター（Colo）](https://developers.cloudflare.com/waf/rate-limiting-rules/request-rate/)ごとに処理されます。（データセンターを超えて協働するわけではありません）
> The Cloudflare data center ID (cf.colo.id) is a mandatory characteristic of every rate limiting rule to ensure that counters are not shared across data centers. This characteristic does not appear in the rule configuration in the dashboard, but you must include it when creating rate limiting rules via API.

`With the same characteristics...`  には `cf.colo.id` が[暗黙の条件として定義](https://developers.cloudflare.com/waf/rate-limiting-rules/parameters/)されています。（API で設定を取ると指定されていることがわかります）
送信元 IP が同じ場合、リクエストの到達するデータセンターが変わることはほぼないので、分別に影響はなさそうです。

なお Eyeball が接続している Colo は /cdn-cgi/trace で確認できます。
```shell:colo
#東京から
~$ curl -s https://ec2.oyama.cf/cdn-cgi/trace|grep colo
colo=NRT

#ブラジルから
~$ curl -s https://ec2.oyama.cf/cdn-cgi/trace|grep colo
colo=GRU
```

リクエストの特徴分けに使える Field は[後述](#特徴識別に使える-expression-field)します。

また `Use custom counting expression` をクリックすると、カウント条件を変更することができます。

### カウント条件

カウント条件の[デフォルト](https://developers.cloudflare.com/waf/rate-limiting-rules/parameters/)は入力マッチルールです。
ここでは下記になります。

`(http.host eq "ec2.oyama.cf")`

つまり


- `(http.host eq "ec2.oyama.cf")` をレートリミットの対象にして
- `cf.colo.id と ip.src （AND 条件）`でクラスを分けて
- `(http.host eq "ec2.oyama.cf")` であれば、カウントする

というルールになります。

カウント条件を変更する例は[後述](#カウント条件の変更同じ-ip-からの通信を他の条件でクラス分け)します。

## レートリミット（When rate exceeds...）
レートリミットのしきい値と測定間隔を定義します。
<img width="600" alt="Screenshot 2023-10-07 at 12.40.18.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2218045/f627749f-cbfd-df56-1966-f7c46b869d2e.png">

表示のままです。
10 秒間に 5 リクエストを超えたら... となります。

測定間隔は下記が指定できます。（[プラン](https://developers.cloudflare.com/waf/rate-limiting-rules/#availability)によります）
<img width="100" alt="Screenshot 2023-10-07 at 12.44.13.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2218045/9ed3e36c-9f23-5ab2-7369-7031d7983fad.png">

## アクション（Then take action...）
リクエストがしきい値を超えた場合の処理を定義します。
<img width="600" alt="Screenshot 2023-10-07 at 12.44.59.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2218045/ded537d4-c500-d944-ca74-abf87079000e.png">

レートを超えた場合に、そのクラスに対するアクションを指定します。
この場合、Block で text メッセージを返しています。
使えるアクションは[後述](#アクションの種類)します。

また、全リクエストを一定期間対象にするか、超過分を対象にするかを選ぶことができます。
<img width="600" alt="Screenshot 2023-10-07 at 12.47.35.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2218045/bfc077ca-b56d-22e8-8950-7fbebe30a061.png">
<img width="600" alt="Screenshot 2023-10-07 at 12.47.59.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2218045/e9135214-1e6e-3f02-14d6-2fe0f8229f2c.png">

### 適正なレートを探る
2023 年 9 月の [Blog](https://blog.cloudflare.com/new-rate-limiting-analytics-and-throttling/) のアップデートにありましたが、[Security Analytics](https://blog.cloudflare.com/security-analytics/) のダッシュボードから IP や [JA3 Fingerprint](https://developers.cloudflare.com/bots/concepts/ja3-fingerprint/) でリクエストの統計を[分析する機能](https://developers.cloudflare.com/waf/rate-limiting-rules/find-rate-limit/)が付きました（Enterprise プラン）。
<img width="600" alt="Screenshot 2023-10-07 at 21.52.43.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2218045/aaa9638a-1a18-6fe8-1d94-34edcb853e14.png">

期間中のリクエストを任意のフィルタで抽出し、定義済みの条件（IP、JA3 または IP + JA3）でクラス化、それぞれの単位時間あたりのリクエスト数を確認可能です。

例えば、右ペインで Bot Score 20 以下を選ぶと、その部分だけが抜き出されます。
単位時間の Bot リクエストを把握できるため Bot 制限のためのレート戦略が立てられます。

## 中締め

上記の Rate Limiting ルールを図に落とすと、下記になります。

```mermaid
flowchart LR
    A[リクエスト] -->|着信| B[\入力マッチルール<br>http.host eq ec2.oyama.cf/]
    B --> C{リクエストの特徴で<br>クラス分け<br>cf.colo.id AND ip.src}
    C -->|クラス1| D{レートリミット中?}
    D -->|yes| F(アクション<br><br>ブロック 10秒)
    D -->|no| G{カウント条件に合う?<br>http.host eq ec2.oyama.cf}
    G -->|yes| H[カウンター+1 & 通過]
    H -.レートリミットトリガー<br>10秒 5リクエスト.->D
    G -->|no| I[通過]
```
API と対比してみます。

```json:rule
{
    "id": "6ab99a1a40c543598a9606cbac5c5a73",
    "name": "default",
    "description": "",
    "source": "rate_limit",
    "kind": "zone",
    "version": "41",
    "rules": [
      {
        "id": "e0dd26df949d41bb868b37f445f23b97",
        "version": "9",
        "action": "block",
        "ratelimit": {
          "characteristics": [                             <--- クラス分け
            "ip.src",
            "cf.colo.id"
          ],
          "period": 10,
          "requests_per_period": 5,
          "mitigation_timeout": 10
        },
        "expression": "(http.host eq \"ec2.oyama.cf\")",   <--- 入力マッチ, カウント
        "description": "adrl test",
        "last_updated": "2023-10-07T06:48:46.295931Z",
        "ref": "e0dd26df949d41bb868b37f445f23b97",
        "enabled": true,
        "action_parameters": {                             <--- アクション
          "response": {
            "status_code": 429,
            "content": "b",
            "content_type": "text/plain"
          }
        }
      },
```

## 動作の例
### 同じ IP からのリクエスト
<img width="600" alt="Screenshot 2023-10-07 at 15.44.37.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2218045/7b10b0fd-7053-220f-4663-4378405f703f.png">

同じ IP の 2 つのターミナルから 1 秒おきにリクエストを送ってますが、左は 2 個、右は 3 個（合計 5 ）でブロックが開始されました。
リクエストが同じクラスに分類されていることがわかります。

### 違う IP からのリクエスト
<img width="600" alt="Screenshot 2023-10-07 at 15.59.50.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2218045/7caa591e-7b68-aabf-c378-3bf93a141a14.png">

違う IP からリクエストを送ります。
お互いにおおよそ 5 リクエスト程度でブロックが開始されました。
リクエストが異なるクラスに分類されていることがわかります。

### カウント条件の変更（同じ IP からの通信を他の条件でクラス分け）

Mac とその上の仮想マシンからリクエストをしていますが、同じ IP を使う環境となっています。

```
# Mac
~ $ curl -V
curl 8.2.1 (x86_64-apple-darwin22.4.0)

# 仮想マシン
keio@vm1:~$ curl -V
curl 7.81.0 (x86_64-pc-linux-gnu)
```

何かしら区別できるか、Cloudflare の [Analytics](https://developers.cloudflare.com/analytics/account-and-zone-analytics/zone-analytics/) からドリルダウンしてみます。
User Agent あるいは JA3 Fingerprint（[Bot Management 契約の Enterprise プラン](https://developers.cloudflare.com/bots/concepts/ja3-fingerprint/)）に 2 種類出てきています。
これらを条件に入れることで、同じ IP でもリクエストを区別ができそうです。
<img width="200" alt="Screenshot 2023-10-08 at 11.24.36.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2218045/d4ae822e-746b-c7a8-0ccb-b14282f59a9c.png">

User Agent は簡単に変更できるので、JA3 Fingerprint を使ってクラス分けをしようと思います。JA3 Finterprint の 014 始まりが Mac curl の通信です。
<img width="600" alt="Screenshot 2023-10-08 at 11.28.19.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2218045/346d2a4d-5e1e-5c8e-e752-b21e937da389.png">

レートリミットの設定は、クラス分けに JA3 Fingerprint を追加、Mac curl のときのみカウントし、アクションに当たるようにします。
<img width="600" alt="Screenshot 2023-10-07 at 16.23.45.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2218045/f81b9416-345d-c3d2-fc3a-9cd7406bb353.png">

```json:API
        "ratelimit": {
          "characteristics": [                             <--- クラス分け
            "ip.src",
            "cf.bot_management.ja3_hash",
            "cf.colo.id"
          ],
          "period": 10,
          "requests_per_period": 5,
          "mitigation_timeout": 10,
          "counting_expression": "(cf.bot_management.ja3_hash eq \"0149f47eabf9a20d0893e2a44e5a6323\")"  <--- カウント
        },
```
クラス分けおよびカウント条件をカスタムしたことで、下記の動作に変わります。

```mermaid
flowchart LR
    A[リクエスト] -->|着信| B[\入力マッチルール<br>http.host eq ec2.oyama.cf/]
    B --> C{リクエストの特徴で<br>クラス分け<br>cf.colo.id AND ip.src AND cf.bot_management.ja3_hash}
    C -->|クラス1| D{レートリミット中?}
    subgraph クラス1
    D -->|yes| F(アクション<br><br>ブロック 10秒)
    D -->|no| G{カウント条件に合う?<br>cf.bot_management.ja3_hash eq 0149f47eabf9a20d0893e2a44e5a6323}
    G -->|yes| H[カウンター+1 & 通過]
    H -.レートリミットトリガー<br>10秒 5リクエスト.->D
    G -->|no| I[通過]
    end
    C -->|クラス2| J{レートリミット中?}
    subgraph クラス2
    J -->|yes| K(アクション)
    J -->|no| L{カウント条件に合う?<br>cf.bot_management.ja3_hash eq 0149f47eabf9a20d0893e2a44e5a6323}
    L -->|yes| M[カウンター+1 & 通過]
    M -.レートリミットトリガー<br>10秒 5リクエスト.->J
    L -->|no| N[通過]
    end
```
同じ IP でも仮想マシンの方は制限されなくなりました。
<img width="600" alt="Screenshot 2023-10-07 at 16.26.59.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2218045/21e7278a-a179-48aa-c960-06f2acc5a242.png">

カウントに使える条件は[後述](#カウント条件に使える-expression-field)しますが、入力マッチの条件との違いはレスポンスを見れることです。

#### レスポンスを条件に

カウンターの加算には Eyeball からのリクエストだけでなく、オリジンサーバーからのレスポンス（ヘッダー・ステータスコード）を[指定する](https://developers.cloudflare.com/waf/rate-limiting-rules/request-rate/)ことができます。
オリジンサーバーの負荷などをもとにレートリミットしたい場合に使えます。
<img width="600" alt="Screenshot 2023-10-07 at 17.05.28.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2218045/98f078fe-6da1-3f64-f7c8-999a708c15e4.png">

同じホストからのリクエストでもオリジンサーバーからのステータスコードが 200 の場合通過しますが、500 の戻りがしきい値を超えると Block が発動しています（429）。

```shell:ステータスコードによる比較
#ステータスコード 200 レートリミットなし
~ $ while true; do curl "https://www2.oyama.cf/?code=200" -svo /dev/null 2>&1 | grep "< HTTP/2"; sleep 1; done
< HTTP/2 200
< HTTP/2 200
< HTTP/2 200
< HTTP/2 200
< HTTP/2 200
< HTTP/2 200
< HTTP/2 200
< HTTP/2 200
< HTTP/2 200
< HTTP/2 200
< HTTP/2 200
< HTTP/2 200
< HTTP/2 200
< HTTP/2 200
< HTTP/2 200

#ステータスコード 500 レートリミットあり
~ $ while true; do curl "https://www2.oyama.cf/?code=500" -svo /dev/null 2>&1 | grep "< HTTP/2"; sleep 1; done
< HTTP/2 500
< HTTP/2 500
< HTTP/2 500
< HTTP/2 500
< HTTP/2 500
< HTTP/2 500
< HTTP/2 500
< HTTP/2 429  <‐‐‐ レートリミット開始
< HTTP/2 429
< HTTP/2 429
< HTTP/2 429
< HTTP/2 429
< HTTP/2 429
< HTTP/2 429
< HTTP/2 429
< HTTP/2 500  <‐‐‐ レートリミット解除
< HTTP/2 500
< HTTP/2 500
< HTTP/2 500
< HTTP/2 500
< HTTP/2 500
< HTTP/2 500
< HTTP/2 429
< HTTP/2 429
```


## まとめ
アプリケーションへのリクエスト着信をレートという観点で分類・分析し、オリジンサーバーへ流入をコントロールすることができるツールだと思います。
どのような使いようができるか、サービス提供側でしか思いつかないアイデアもあるかと思うので、ぜひ工夫いただければと思います。

## 補足
### ユースケース・ベストプラクティス
環境や目的に合わせて柔軟に構成ができるツールです。
本家のサンプルにアイデアの元があるかもしれません。

https://blog.cloudflare.com/tag/rate-limiting/

https://developers.cloudflare.com/waf/rate-limiting-rules/best-practices/

### プラン別の比較
Enterprise プランで試しました。
Rate Limiting 機能のプラン別の比較はこちらです。

https://developers.cloudflare.com/waf/rate-limiting-rules/#availability

### IP with NAT support って何？

Enterprise プランの場合、特徴でのクラス分けに [IP with NAT support](https://developers.cloudflare.com/waf/rate-limiting-rules/parameters/) ってのがあります。単なる IP と何が違うんでしょうか。
> Use IP with NAT support to handle situations such as requests under NAT sharing the same IP address. Cloudflare uses a variety of privacy-preserving techniques to identify unique visitors, which may include use of session cookies. Refer to Cloudflare Cookies for details.

[CGNAT](https://www.nic.ad.jp/ja/basics/terms/cgn.html) などの IP 共有状態でもなるべく Eyeball を区別しようとする試みで、HTTP ヘッダーが使われるようです。

特徴を IP から IP with NAT support に変えてみます。
<img width="600" alt="Screenshot 2023-10-07 at 17.41.37.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2218045/a0e742d7-7436-618f-a717-b39735b56db9.png">

```json:API
        "ratelimit": {
          "characteristics": [
            "cf.unique_visitor_id",      <--- IP with NAT support
            "cf.colo.id"
          ],
```
すると、下記のようにレスポンスに新しい set-cookie が付与され始めます。
この [_cfuvid](https://developers.cloudflare.com/fundamentals/reference/policies-compliances/cloudflare-cookies/#_cfuvid-for-rate-limiting-rules) が Rate Limiting で NAT を意識した区別のもとになるようです。
```
< set-cookie: _cfuvid=BOKA7bH54GOUXXSD1KbDv16H9euO6x_nkBh3IkJf650-1696666988432-0-604800000; path=/; domain=.oyama.cf; HttpOnly; Secure; SameSite=None
```
同じ IP からの通信の片方に _cfuvid Cookie を付けてみると、リクエストが独立して処理されます。Cookie を認識して別のクラスに分けられていますね。
<img width="600" alt="Screenshot 2023-10-07 at 17.46.28.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2218045/bdc25c5f-326b-8876-01f1-d3897f18f3bf.png">

ただ、Cookie をつけてこない Eyeball はこれでは区別ができないですね。
[Rate Limiting (previous version)](https://developers.cloudflare.com/waf/reference/legacy/old-rate-limiting/) の場合は [_cfruid](https://developers.cloudflare.com/fundamentals/reference/policies-compliances/cloudflare-cookies/#__cfruid-to-support-cloudflare-rate-limiting-previous-version) となります。

### 入力マッチに使える Expression Field

入力マッチ `If incoming requests match...` のフィルターに指定できる [Fields](https://developers.cloudflare.com/ruleset-engine/rules-language/fields/) は [GUI のビルダー](https://developers.cloudflare.com/ruleset-engine/rules-language/expressions/edit-expressions/) に出てきたものだと下記あたりでした。

- 送信元 IP 関連
- HTTP ヘッダー・ボディ関連
- [Bot スコア](https://developers.cloudflare.com/bots/concepts/bot-score/)（Bot management 有効時）
- [脅威スコア](https://developers.cloudflare.com/bots/troubleshooting/#what-is-the-difference-between-the-threat-score-and-bot-management-score)（IP Reputation）
- [WAF attack スコア](https://developers.cloudflare.com/waf/about/waf-attack-score/)

契約サービスにより増減があるので、あくまで参考まで。

[オペレーター](https://developers.cloudflare.com/ruleset-engine/rules-language/operators/)は適当につけています。
下記のルール、一行一行を AND OR で組み合わせることができます。
```
ip.geoip.country in {"JP" "KR"}
ip.geoip.continent eq "AS"
ip.geoip.asnum eq 1
ip.src in {192.0.2.1 192.0.2.2}

ssl

http.cookie eq "name=value"
http.host contains "ec2"
http.referer contains "example"
http.request.method in {"GET" "PUT"}
not http.request.version in {"HTTP/1.0"}
http.request.full_uri contains "https://example.com/contact?page=1234" 
http.request.uri contains "/content?page=1234"
http.request.uri.path eq "/content"
starts_with(http.request.uri.query, "page=1234")
http.user_agent matches ".*MSIE [8-9].*"
all(http.request.headers["x-hoge"][*] ne "moge")
http.request.body.size lt 100
http.request.body.mime eq " image/jpeg"
http.request.body.raw matches "^a" 
lookup_json_string(http.request.body.raw, "key") eq "value"
http.x_forwarded_for eq "192.0.2.1"

cf.tls_client_auth.cert_verified
not cf.client.bot
cf.bot_management.score le 20
cf.bot_management.ja3_hash eq "df669e7ea913f1ac0c0cce9a201a2ec1"
not cf.bot_management.verified_bot
not cf.bot_management.static_resource
cf.threat_score lt 20
cf.waf.score le 10
cf.waf.score.rce eq 5
cf.waf.score.sqli eq 5
cf.waf.score.xss eq 5
```

### 特徴識別に使える Expression Field

リクエストの特徴でクラスを分ける `With the same characteristics...` では下記が[指定](https://developers.cloudflare.com/waf/rate-limiting-rules/parameters)できます。

```json:
[
  {
    "Dashboard value": "N/A (implicitly included)",
    "API value": "cf.colo.id (mandatory)"
  },
  {
    "Dashboard value": "IP",
    "API value": "ip.src"
  },
  {
    "Dashboard value": "IP with NAT support",
    "API value": "cf.unique_visitor_id"
  },
  {
    "Dashboard value": "Header value of (enter header name)",
    "API value": "http.request.headers[\"<header_name>\"]"
  },
  {
    "Dashboard value": "Cookie value of (enter cookie name)",
    "API value": "http.request.cookies[\"<cookie_name>\"]"
  },
  {
    "Dashboard value": "Query value of (enter parameter name)",
    "API value": "http.request.uri.args[\"<query_param_name>\"]"
  },
  {
    "Dashboard value": "Host",
    "API value": "http.host"
  },
  {
    "Dashboard value": "Path",
    "API value": "http.request.uri.path"
  },
  {
    "Dashboard value": "AS Num",
    "API value": "ip.geoip.asnum"
  },
  {
    "Dashboard value": "Country",
    "API value": "ip.geoip.country"
  },
  {
    "Dashboard value": "JA3 Fingerprint",
    "API value": "cf.bot_management.ja3_hash"
  },
  {
    "Dashboard value": "JSON string value of (enter key)",
    "API value": "lookup_json_string(http.request.body.raw, \"<key>\")"
  },
  {
    "Dashboard value": "N/A (API only)",
    "API value": "lookup_json_integer(http.request.body.raw, \"<key>\")"
  },
  {
    "Dashboard value": "Body",
    "API value": "http.request.body.raw"
  },
  {
    "Dashboard value": "Body size (select operator, enter size)",
    "API value": "http.request.body.size"
  },
  {
    "Dashboard value": "Form input value of (enter field name)",
    "API value": "http.request.body.form[\"<input_field_name>\"]"
  },
  {
    "Dashboard value": "N/A (API only)",
    "API value": "substring(<field>, <start>[, <end>])"
  }
]
```

### カウント条件に使える Expression Field

カウント条件をカスタム `Increment counter when…` する場合、入力マッチで利用できる Fields に加えて、レスポンスが追加されています。
```
(any(http.response.headers["x-hoge"][*] eq "moge")
http.response.code eq 500)
```
上述の通り、デフォルトは入力マッチ条件がそのままカウント条件になります。

### アクションの種類
使えるアクションは下記の通りです。Block については[オプション](https://developers.cloudflare.com/waf/rate-limiting-rules/create-account-dashboard/#configuring-a-custom-response-for-blocked-requests)があります。
<img width="600" alt="Screenshot 2023-10-07 at 22.50.33.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2218045/fd781565-fc20-11c1-d020-4a8a5b68267d.png">

Rulesets 全体のアクションの説明は[こちら](https://developers.cloudflare.com/ruleset-engine/rules-language/actions/)。

### 設定の適用ポイント

Rate Limiting Rules を [Zone](https://developers.cloudflare.com/waf/rate-limiting-rules/create-zone-dashboard/) に適用しましたが、[Account](https://developers.cloudflare.com/waf/rate-limiting-rules/create-account-dashboard/) にも適用可能です。

### オリジンサーバーが API を提供する場合

[API Shield](https://developers.cloudflare.com/api-shield/) というプロダクトは機械学習によって API エンドポイントのレートを[学習](https://developers.cloudflare.com/api-shield/get-started/#allow-the-system-to-learn-your-traffic-patterns)し、この Rate Limiting Rules を[利用](https://developers.cloudflare.com/api-shield/security/volumetric-abuse-detection/)します。
Bot Managment など他のプロダクトとの連携で API を[セキュアに保ち](https://developers.cloudflare.com/api-shield/security/)ます。