Cloudflare HTTP DDoS Attack Protection Managed Ruleset の挙動を確認する

# Cloudflare HTTP DDoS Attack Protection Managed Ruleset とは

> - ブログ -  [How to customize your HTTP DDoS protection settings](https://blog.cloudflare.com/http-ddos-managed-rules/)
> - 公式ドキュメント - [HTTP DDoS Attack Protection Managed Ruleset · Cloudflare DDoS Protection docs](https://developers.cloudflare.com/ddos-protection/managed-rulesets/http/)

これまで Cloudflare の DDoS 保護ルールはブラックボックスでしたが、HTTP DDoS に関してはマネージドルールの一覧がユーザーに公開され、カスタマイズもできるようになりました。



# ダッシュボードでルール情報を確認

https://dash.cloudflare.com/?to=/:account/:zone/security/ddos から確認できます。

![image-20220511002443210](https://cdn.jsdelivr.net/gh/kyouheicf/image@master/uPic/image-20220511002443210.png)

その中から Test rule を使って挙動の確認ができます。

![image-20220511002639029](https://cdn.jsdelivr.net/gh/kyouheicf/image@master/uPic/image-20220511002639029.png)

# API でルール情報を確認

API からも取得できる情報を確認しましょう。

> [Cloudflare を CLI で操作する - Qiita](https://qiita.com/khayama/items/c1030886079816d6d8a0)

```shell
export ZONE_ID='YOUR_ZONE_ID'
cli4 zones/:$ZONE_ID/rulesets | jq -r '.[] | select (.phase=="ddos_l7")'
```

```json
{
  "description": "Automatic mitigation of HTTP-based DDoS attacks. Cloudflare routinely adds signatures to address new attack vectors. Additional configuration allows you to customize the sensitivity of each rule and the performed mitigation action.",
  "id": "4d21379b4f9f4bb088e0729962c8b3cf",
  "kind": "managed",
  "last_updated": "2022-05-10T14:30:42.926686Z",
  "name": "DDoS L7 ruleset",
  "phase": "ddos_l7",
  "version": "636"
}
```

ルール一覧の中に先ほどの Test rule も確認できます。

```shell
cli4 zones/:$ZONE_ID/rulesets/:4d21379b4f9f4bb088e0729962c8b3cf | jq -r '.rules[] | select (.categories[]=="test")'
```

```json
{
  "action": "block",
  "categories": [
    "test"
  ],
  "description": "Test rule: will quickly block URI containing 'blockme=npvenJAo9gMlnd5yD37xQ9P2qp3934'.",
  "enabled": true,
  "id": "ca3c07df048b4c2c9c9350116f9d3516",
  "last_updated": "2022-05-10T14:30:42.926686Z",
  "ref": "GEN0006",
  "version": "326"
}
```

# テストルールを使った挙動の確認

具体的な閾値は公開されていませんが、テスト用にトリガーされやすい（？）ルールとなっているようです。

以下のスクリプトを流して確認します。後半は 403 でブロックされたことがわかります。

```shell
export FQDN='example.com'

for i in {1..200}; \
do echo $i $(curl 'https://'$FQDN'/?blockme=npvenJAo9gMlnd5yD37xQ9P2qp3934' -v -s 2>&1 | grep '< HTTP/'); done
```

```shell:コマンド1回目結果
1 < HTTP/2 200 
2 < HTTP/2 200 
3 < HTTP/2 200 
4 < HTTP/2 200 
5 < HTTP/2 200 
6 < HTTP/2 200 
7 < HTTP/2 200 
8 < HTTP/2 200 
9 < HTTP/2 200 
10 < HTTP/2 200 
11 < HTTP/2 200 
12 < HTTP/2 200 
13 < HTTP/2 200 
14 < HTTP/2 200 
15 < HTTP/2 200 
16 < HTTP/2 200 
17 < HTTP/2 200 
18 < HTTP/2 200 
19 < HTTP/2 200 
20 < HTTP/2 200 
21 < HTTP/2 200 
22 < HTTP/2 200 
23 < HTTP/2 200 
24 < HTTP/2 200 
25 < HTTP/2 200 
26 < HTTP/2 200 
27 < HTTP/2 200 
28 < HTTP/2 200 
29 < HTTP/2 200 
30 < HTTP/2 200 
31 < HTTP/2 200 
32 < HTTP/2 200 
33 < HTTP/2 200 
34 < HTTP/2 200 
35 < HTTP/2 200 
36 < HTTP/2 200 
37 < HTTP/2 200 
38 < HTTP/2 200 
39 < HTTP/2 200 
40 < HTTP/2 200 
41 < HTTP/2 200 
42 < HTTP/2 200 
43 < HTTP/2 200 
44 < HTTP/2 200 
45 < HTTP/2 200 
46 < HTTP/2 200 
47 < HTTP/2 200 
48 < HTTP/2 200 
49 < HTTP/2 200 
50 < HTTP/2 200 
51 < HTTP/2 200 
52 < HTTP/2 200 
53 < HTTP/2 200 
54 < HTTP/2 200 
55 < HTTP/2 200 
56 < HTTP/2 200 
57 < HTTP/2 200 
58 < HTTP/2 200 
59 < HTTP/2 200 
60 < HTTP/2 200 
61 < HTTP/2 200 
62 < HTTP/2 200 
63 < HTTP/2 200 
64 < HTTP/2 200 
65 < HTTP/2 200 
66 < HTTP/2 200 
67 < HTTP/2 200 
68 < HTTP/2 200 
69 < HTTP/2 200 
70 < HTTP/2 200 
71 < HTTP/2 200 
72 < HTTP/2 200 
73 < HTTP/2 200 
74 < HTTP/2 200 
75 < HTTP/2 200 
76 < HTTP/2 200 
77 < HTTP/2 200 
78 < HTTP/2 200 
79 < HTTP/2 200 
80 < HTTP/2 200 
81 < HTTP/2 200 
82 < HTTP/2 200 
83 < HTTP/2 200 
84 < HTTP/2 200 
85 < HTTP/2 200 
86 < HTTP/2 200 
87 < HTTP/2 200 
88 < HTTP/2 200 
89 < HTTP/2 200 
90 < HTTP/2 200 
91 < HTTP/2 200 
92 < HTTP/2 200 
93 < HTTP/2 200 
94 < HTTP/2 200 
95 < HTTP/2 200 
96 < HTTP/2 200 
97 < HTTP/2 200 
98 < HTTP/2 200 
99 < HTTP/2 200 
100 < HTTP/2 200 
101 < HTTP/2 200 
102 < HTTP/2 200 
103 < HTTP/2 200 
104 < HTTP/2 200 
105 < HTTP/2 200 
106 < HTTP/2 200 
107 < HTTP/2 200 
108 < HTTP/2 200 
109 < HTTP/2 200 
110 < HTTP/2 200 
111 < HTTP/2 200 
112 < HTTP/2 200 
113 < HTTP/2 200 
114 < HTTP/2 200 
115 < HTTP/2 200 
116 < HTTP/2 200 
117 < HTTP/2 200 
118 < HTTP/2 200 
119 < HTTP/2 200 
120 < HTTP/2 200 
121 < HTTP/2 200 
122 < HTTP/2 200 
123 < HTTP/2 200 
124 < HTTP/2 200 
125 < HTTP/2 200 
126 < HTTP/2 200 
127 < HTTP/2 200 
128 < HTTP/2 200 
129 < HTTP/2 200 
130 < HTTP/2 200 
131 < HTTP/2 200 
132 < HTTP/2 200 
133 < HTTP/2 200 
134 < HTTP/2 200 
135 < HTTP/2 200 
136 < HTTP/2 200 
137 < HTTP/2 200 
138 < HTTP/2 200 
139 < HTTP/2 200 
140 < HTTP/2 200 
141 < HTTP/2 200 
142 < HTTP/2 200 
143 < HTTP/2 200 
144 < HTTP/2 200 
145 < HTTP/2 200 
146 < HTTP/2 200 
147 < HTTP/2 200 
148 < HTTP/2 200 
149 < HTTP/2 200 
150 < HTTP/2 200 
151 < HTTP/2 200 
152 < HTTP/2 200 
153 < HTTP/2 200 
154 < HTTP/2 200 
155 < HTTP/2 200 
156 < HTTP/2 200 
157 < HTTP/2 200 
158 < HTTP/2 200 
159 < HTTP/2 200 
160 < HTTP/2 200 
161 < HTTP/2 200 
162 < HTTP/2 200 
163 < HTTP/2 200 
164 < HTTP/2 200 
165 < HTTP/2 200 
166 < HTTP/2 200 
167 < HTTP/2 200 
168 < HTTP/2 200 
169 < HTTP/2 200 
170 < HTTP/2 200 
171 < HTTP/2 200 
172 < HTTP/2 200 
173 < HTTP/2 200 
174 < HTTP/2 200 
175 < HTTP/2 200 
176 < HTTP/2 200 
177 < HTTP/2 200 
178 < HTTP/2 200 
179 < HTTP/2 200 
180 < HTTP/2 200 
181 < HTTP/2 200 
182 < HTTP/2 200 
183 < HTTP/2 200 
184 < HTTP/2 200 
185 < HTTP/2 200 
186 < HTTP/2 200 
187 < HTTP/2 200 
188 < HTTP/2 200 
189 < HTTP/2 200 
190 < HTTP/2 403 
191 < HTTP/2 200 
192 < HTTP/2 200 
193 < HTTP/2 200 
194 < HTTP/2 200 
195 < HTTP/2 200 
196 < HTTP/2 200 
197 < HTTP/2 200 
198 < HTTP/2 200 
199 < HTTP/2 403 
200 < HTTP/2 403 
```

```shell:コマンド2回目結果
1 < HTTP/2 403 
2 < HTTP/2 403 
3 < HTTP/2 403 
4 < HTTP/2 403 
5 < HTTP/2 403 
6 < HTTP/2 403 
7 < HTTP/2 200 
8 < HTTP/2 403 
9 < HTTP/2 403 
10 < HTTP/2 403 
11 < HTTP/2 403 
12 < HTTP/2 403 
13 < HTTP/2 403 
14 < HTTP/2 403 
15 < HTTP/2 403 
16 < HTTP/2 403 
17 < HTTP/2 403 
18 < HTTP/2 403 
19 < HTTP/2 403 
20 < HTTP/2 200 
21 < HTTP/2 403 
22 < HTTP/2 200 
23 < HTTP/2 403 
24 < HTTP/2 403 
25 < HTTP/2 200 
26 < HTTP/2 403 
27 < HTTP/2 403 
28 < HTTP/2 200 
29 < HTTP/2 403 
30 < HTTP/2 403 
31 < HTTP/2 403 
32 < HTTP/2 403 
33 < HTTP/2 403 
34 < HTTP/2 200 
35 < HTTP/2 403 
36 < HTTP/2 403 
37 < HTTP/2 403 
38 < HTTP/2 403 
39 < HTTP/2 200 
40 < HTTP/2 403 
41 < HTTP/2 200 
42 < HTTP/2 403 
43 < HTTP/2 403 
44 < HTTP/2 403 
45 < HTTP/2 403 
46 < HTTP/2 403 
47 < HTTP/2 403 
48 < HTTP/2 403 
49 < HTTP/2 403 
50 < HTTP/2 403 
51 < HTTP/2 403 
52 < HTTP/2 403 
53 < HTTP/2 403 
54 < HTTP/2 403 
55 < HTTP/2 403 
56 < HTTP/2 403 
57 < HTTP/2 403 
58 < HTTP/2 403 
59 < HTTP/2 403 
60 < HTTP/2 403 
61 < HTTP/2 403 
62 < HTTP/2 403 
63 < HTTP/2 200 
64 < HTTP/2 403 
65 < HTTP/2 403 
66 < HTTP/2 403 
67 < HTTP/2 403 
68 < HTTP/2 403 
69 < HTTP/2 200 
70 < HTTP/2 403 
71 < HTTP/2 403 
72 < HTTP/2 403 
73 < HTTP/2 403 
74 < HTTP/2 403 
75 < HTTP/2 403 
76 < HTTP/2 403 
77 < HTTP/2 403 
78 < HTTP/2 403 
79 < HTTP/2 403 
80 < HTTP/2 403 
81 < HTTP/2 403 
82 < HTTP/2 403 
83 < HTTP/2 403 
84 < HTTP/2 403 
85 < HTTP/2 403 
86 < HTTP/2 403 
87 < HTTP/2 403 
88 < HTTP/2 403 
89 < HTTP/2 403 
90 < HTTP/2 403 
91 < HTTP/2 403 
92 < HTTP/2 403 
93 < HTTP/2 403 
94 < HTTP/2 403 
95 < HTTP/2 403 
96 < HTTP/2 403 
97 < HTTP/2 403 
98 < HTTP/2 403 
99 < HTTP/2 403 
100 < HTTP/2 403 
101 < HTTP/2 403 
102 < HTTP/2 403 
103 < HTTP/2 403 
104 < HTTP/2 403 
105 < HTTP/2 403 
106 < HTTP/2 403 
107 < HTTP/2 403 
108 < HTTP/2 403 
109 < HTTP/2 403 
110 < HTTP/2 403 
111 < HTTP/2 403 
112 < HTTP/2 403 
113 < HTTP/2 403 
114 < HTTP/2 403 
115 < HTTP/2 403 
116 < HTTP/2 403 
117 < HTTP/2 403 
118 < HTTP/2 403 
119 < HTTP/2 403 
120 < HTTP/2 403 
121 < HTTP/2 403 
122 < HTTP/2 403 
123 < HTTP/2 403 
124 < HTTP/2 403 
125 < HTTP/2 403 
126 < HTTP/2 403 
127 < HTTP/2 403 
128 < HTTP/2 403 
129 < HTTP/2 403 
130 < HTTP/2 403 
131 < HTTP/2 403 
132 < HTTP/2 403 
133 < HTTP/2 403 
134 < HTTP/2 403 
135 < HTTP/2 403 
136 < HTTP/2 403 
137 < HTTP/2 403 
138 < HTTP/2 403 
139 < HTTP/2 403 
140 < HTTP/2 403 
141 < HTTP/2 403 
142 < HTTP/2 403 
143 < HTTP/2 403 
144 < HTTP/2 403 
145 < HTTP/2 403 
146 < HTTP/2 403 
147 < HTTP/2 403 
148 < HTTP/2 403 
149 < HTTP/2 403 
150 < HTTP/2 403 
151 < HTTP/2 403 
152 < HTTP/2 403 
153 < HTTP/2 403 
154 < HTTP/2 403 
155 < HTTP/2 403 
156 < HTTP/2 403 
157 < HTTP/2 403 
158 < HTTP/2 403 
159 < HTTP/2 403 
160 < HTTP/2 403 
161 < HTTP/2 403 
162 < HTTP/2 403 
163 < HTTP/2 403 
164 < HTTP/2 403 
165 < HTTP/2 403 
166 < HTTP/2 403 
167 < HTTP/2 403 
168 < HTTP/2 403 
169 < HTTP/2 403 
170 < HTTP/2 403 
171 < HTTP/2 403 
172 < HTTP/2 403 
173 < HTTP/2 403 
174 < HTTP/2 403 
175 < HTTP/2 403 
176 < HTTP/2 403 
177 < HTTP/2 403 
178 < HTTP/2 403 
179 < HTTP/2 403 
180 < HTTP/2 403 
181 < HTTP/2 403 
182 < HTTP/2 403 
183 < HTTP/2 403 
184 < HTTP/2 403 
185 < HTTP/2 403 
186 < HTTP/2 403 
187 < HTTP/2 403 
188 < HTTP/2 403 
189 < HTTP/2 403 
190 < HTTP/2 403 
191 < HTTP/2 403 
192 < HTTP/2 403 
193 < HTTP/2 403 
194 < HTTP/2 403 
195 < HTTP/2 403 
196 < HTTP/2 403 
197 < HTTP/2 403 
198 < HTTP/2 403 
199 < HTTP/2 403 
200 < HTTP/2 403 
```

また、実際にアクセスしてみると、このようなページになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/21a56241-5213-c7e1-a3a8-5d4fc24bb5b7.png)


# ダッシュボードで結果を確認

https://dash.cloudflare.com/?to=/:account/:zone/security

![image-20220511004636107](https://cdn.jsdelivr.net/gh/kyouheicf/image@master/uPic/image-20220511004636107.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/d1444436-e32b-be6e-cf2b-c0733112223f.png)

![image-20220511004833935](https://cdn.jsdelivr.net/gh/kyouheicf/image@master/uPic/image-20220511004833935.png)

# 通知

こちらの KB を参考にして、事前に DDoS アラートを構成しておけば、基準を満たした際に以下のようなメール通知を受信することもできました。

検知したルール ID まで含めた詳細な内容のメールとなっているので、助かります。

> [CloudflareのDDoSアラートについて理解する – Cloudflareヘルプセンター](https://support.cloudflare.com/hc/ja/articles/360053216191-Cloudflare%E3%81%AEDDoS%E3%82%A2%E3%83%A9%E3%83%BC%E3%83%88%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6%E7%90%86%E8%A7%A3%E3%81%99%E3%82%8B)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/d22f2d92-a08b-cc82-0040-d874c69c7b49.png)

# 参考：ログ

```json:ddos_log.json
{
  "BotDetectionIDs": [
    33554817
  ],
  "BotScore": 1,
  "BotScoreSrc": "Heuristics",
  "BotTags": [],
  "CacheCacheStatus": "unknown",
  "CacheReserveUsed": false,
  "CacheResponseBytes": 0,
  "CacheResponseStatus": 0,
  "CacheTieredFill": false,
  "ClientASN": 2527,
  "ClientCountry": "jp",
  "ClientDeviceType": "desktop",
  "ClientIP": "x.x.x.x",
  "ClientIPClass": "noRecord",
  "ClientMTLSAuthCertFingerprint": "",
  "ClientMTLSAuthStatus": "unknown",
  "ClientRegionCode": "13",
  "ClientRequestBytes": 2959,
  "ClientRequestHost": "example.com",
  "ClientRequestMethod": "GET",
  "ClientRequestPath": "/",
  "ClientRequestProtocol": "HTTP/2",
  "ClientRequestReferer": "",
  "ClientRequestScheme": "https",
  "ClientRequestSource": "eyeball",
  "ClientRequestURI": "/?blockme=npvenJAo9gMlnd5yD37xQ9P2qp3934",
  "ClientRequestUserAgent": "curl/7.82.0-DEV",
  "ClientSSLCipher": "AEAD-AES128-GCM-SHA256",
  "ClientSSLProtocol": "TLSv1.3",
  "ClientSrcPort": 51071,
  "ClientTCPRTTMs": 5,
  "ClientXRequestedWith": "",
  "ContentScanObjResults": [],
  "ContentScanObjTypes": [],
  "EdgeCFConnectingO2O": false,
  "EdgeColoCode": "NRT",
  "EdgeColoID": 408,
  "EdgeEndTimestamp": 1675178658281000000,
  "EdgePathingOp": "ban",
  "EdgePathingSrc": "protect",
  "EdgePathingStatus": "l7ddos",
  "EdgeRateLimitAction": "",
  "EdgeRateLimitID": 0,
  "EdgeRequestHost": "",
  "EdgeResponseBodyBytes": 1467,
  "EdgeResponseBytes": 2453,
  "EdgeResponseCompressionRatio": 1,
  "EdgeResponseContentType": "text/html",
  "EdgeResponseStatus": 403,
  "EdgeServerIP": "",
  "EdgeStartTimestamp": 1675178658269000000,
  "EdgeTimeToFirstByteMs": 27,
  "FirewallMatchesActions": [
    "block"
  ],
  "FirewallMatchesRuleIDs": [
    "ca3c07df048b4c2c9c9350116f9d3516"
  ],
  "FirewallMatchesSources": [
    "l7ddos"
  ],
  "JA3Hash": "09fa2749da64939e9b4053172a8e78dc",
  "OriginDNSResponseTimeMs": 0,
  "OriginIP": "",
  "OriginRequestHeaderSendDurationMs": 0,
  "OriginResponseBytes": 0,
  "OriginResponseDurationMs": 0,
  "OriginResponseHTTPExpires": "",
  "OriginResponseHTTPLastModified": "",
  "OriginResponseHeaderReceiveDurationMs": 0,
  "OriginResponseStatus": 0,
  "OriginResponseTime": 0,
  "OriginSSLProtocol": "unknown",
  "OriginTCPHandshakeDurationMs": 0,
  "OriginTLSHandshakeDurationMs": 0,
  "ParentRayID": "00",
  "RayID": "792374162a26af42",
  "SecurityLevel": "unk",
  "SmartRouteColoID": 0,
  "UpperTierColoID": 0,
  "WAFAction": "unknown",
  "WAFAttackScore": 87,
  "WAFFlags": "0",
  "WAFMatchedVar": "",
  "WAFProfile": "unknown",
  "WAFRCEAttackScore": 88,
  "WAFRuleID": "",
  "WAFRuleMessage": "",
  "WAFSQLiAttackScore": 98,
  "WAFXSSAttackScore": 98,
  "WorkerCPUTime": 0,
  "WorkerStatus": "unknown",
  "WorkerSubrequest": false,
  "WorkerSubrequestCount": 0,
  "WorkerWallTimeUs": 0,
  "ZoneID": XXXXXXXXX,
  "ZoneName": "example.com"
}
```