Cloudflare の WAF が検知したセキュリティイベントのアラート通知(Notification)を試します。
試験手順
本家ガイド Cloudflare Notifications
- 通知宛先を設定(オプション)
通知先は Email(全プラン), PagerDuty(Businessプラン以上), webhooks(Professionalプラン以上) があります。
Email 以外はあらかじめ通知先を定義します。
2. 実際の通知を作成するため、「通知(Notification)」を追加
Cloudflare プロダクトに関する様々な定義済みのアラート通知を有効にすることができます。
3. WAF アラートの通知タイプを選択
WAF のアラート通知には 2 つのタイプがあります。
今回は検知から通知までの時間も早く、柔軟な設定が可能な高度な方で進めます。
Free プランでも API を利用すれば更に細かい条件を自作アラート通知に組み込めます(後述)
通知先は Email と 1 で作成した webhook を選択しています。
4. アラート通知対象のゾーンとサービスを選択
今回は WAF のカスタムルールが生成したイベントをソースにします。
カスタムルールは firewallCustom になります。
- アラート対象のアクションを絞る場合
イベントに含まれるアクションでアラートを絞りたい場合は選択が可能です。(例えば Block のみ対象にしたい、など)
デフォルトではすべてが対象になります。
これはダッシュボードでイベントを確認する際に、アクションをキーに抽出するのと同じ感覚ですね。
これで通知の作成は終わりです。
5. メイン画面から送信テスト(オプション)
「テスト」をクリックすると擬似的なアラート通知の送信ができます。
6. WAF カスタムルールの作成
実際にアラートを発生させるため、ルールを設定します。
日本からの通信をブロックして、WAF のイベントを発生させるためのルールを作っています。
7. ルールにヒットするリクエストを送信
下記の方針でリクエストを投げました。
- 二つのカスタムルールを用意
- ぞれぞれのルールが生成したイベントを合計し、カスタムルール全体で200を超える程度のリクエストを投げる
200を超えさせる理由は後述
8. WAF アラート通知発動
およそ5分で Email と webhook が到着しました。
アラート通知のロジック(WAF編)
本家解説によると、WAF 関連のアラート通知のロジックについては、下記の数字がポイントになります
数 | 単位 |
---|---|
6 | 時間 |
5 | 分間のバケツ |
200 | セキュリティイベントの数 |
3.5 | z-score |
2 | 時間 |
これらを使ったロジックは下記のとおりです。
- 過去6時間のセキュリティイベント数を5分間隔でカウントし、最新の値が z-score 3.5 以上 かつ イベント数が 200を超えている
- 同じイベントはその後2時間は発動されない
セキュリティイベントのアラート通知に z-score の採用や 200 のしきい値との併用についての背景や理由については、こちらの Cloudflare ブログ が詳しいです。
z-score
イベントのスパイクをシミュレーションしてみましょう。
6時間を5分間隔にすると、72の計測ポイントがあります。
Cloudflare のダッシュボードの WAF イベントでも6時間の範囲にすると、値は5分間分での表示になりますね
アラート通知をトリガーするには、数字を72個並べて、最後の 201 の z-score が 3.5 以上になればよさそうです。(オソラク)
71個の数字を1-120からランダムに並べ、最後の72個めを201にして z-score を取ってみました。
最後の値(201) は 200を超え、かつ、 z-score 3.7 となり 3.5 を超えました。
こういう具合でアラート通知が発動されるんじゃないかと思います。
Rでの計算
> scale(sample)
[,1]
[1,] 0.84778699
[2,] 1.08873698
[3,] 0.55329256
[4,] 1.24937030
[5,] -0.91917958
[6,] -0.43727961
[7,] -1.24044623
[8,] -0.89240736
[9,] 1.54386473
[10,] 0.33911480
[11,] -0.94595180
[12,] 1.57063695
[13,] -1.32076289
[14,] -1.18690179
[15,] -0.49082405
[16,] 0.41943146
[17,] -0.24987406
[18,] -0.78531847
[19,] -1.34753511
[20,] 0.15170925
[21,] -0.54436849
[22,] -1.02626846
[23,] -0.43727961
[24,] -0.35696294
[25,] -0.67822959
[26,] 0.76747033
[27,] -1.45462399
[28,] -1.56171288
[29,] 0.25879813
[30,] 0.41943146
[31,] -0.91917958
[32,] 1.11550920
[33,] -0.99949624
[34,] 0.58006478
[35,] -0.19632962
[36,] -1.10658512
[37,] -1.53494065
[38,] 0.87455921
[39,] 0.33911480
[40,] -0.65145737
[41,] -0.11601296
[42,] 1.24937030
[43,] -0.19632962
[44,] -0.62468515
[45,] 1.27614252
[46,] 0.28557035
[47,] 0.66038144
[48,] -0.94595180
[49,] -0.57114071
[50,] 1.57063695
[51,] 0.84778699
[52,] -1.37430733
[53,] 0.09816481
[54,] -0.91917958
[55,] 1.46354807
[56,] 0.79424255
[57,] 0.60683700
[58,] -1.45462399
[59,] 0.41943146
[60,] -1.18690179
[61,] 0.17848147
[62,] -0.54436849
[63,] -0.19632962
[64,] 0.28557035
[65,] 0.33911480
[66,] 0.41943146
[67,] 0.87455921
[68,] 0.79424255
[69,] 1.06196476
[70,] 0.60683700
[71,] -0.30341850
[72,] 3.76595905
attr(,"scaled:center")
[1] 59.33333
attr(,"scaled:scale")
[1] 37.35215
>
> plot(scale(sample),type="b")
> plot(sample,type="b")
グラフにすると、これくらいのハネ加減になりました。
横軸が6時間で、過去の5分間隔のイベント数が置かれてるイメージです。
なお、トリガーについては、各アラート通知でそのソースイベントの性質と通知の目的によってロジックが異なります。
あくまで上記は WAF 関連のものになります。
オリジンエラーレートの例
自前でモニターの例
Analytics API(Free プランでも使える)
Analytics API でもダッシュボードと同じ様な WAF 関連の統計情報がとれます。
色々な視点からデータを分析できますので、自身で好きなトリガーを作ることができそうです。また、こちらはプランに関係なく利用できるのが利点です。
- WAF アラート通知よりも細かい条件でソースを作成することができる
(下記の例では、WAF アラートにはついてない、ホスト名での絞り込みを実施) - 通知の仕組みは別途用意する必要があります
下記では、直近5分で特定ホストに対してカスタムルールでブロックまたはマネージドチャレンジしたイベントの数、を取ることができます。(macOS で実施)
dt2=`date -Iseconds`
dt1=`date -Iseconds -v-5M`
cred="<TOKEN>"
ztag="<ZONEID>"
wafsrc="firewallCustom"
action='[\"block\",\"managed_challenge\"]'
dhost="www.example.com"
curl "https://api.cloudflare.com/client/v4/graphql" -H "Authorization: Bearer $cred" -H "Content-Type: application/json" -d '{"query":"{viewer{zones(filter:{zoneTag:\"'$ztag'\"}){firewallEventsAdaptiveByTimeGroups(filter:{source:\"'$wafsrc'\",datetime_geq:\"'$dt1'\",datetime_lt:\"'$dt2'\",clientRequestHTTPHost:\"'$dhost'\",action_in:'$action'},limit:1,orderBy:[datetimeFiveMinutes_DESC]){count,dimensions{datetimeFiveMinutes}}}}}"}'
1分の場合(Linux で実施)
dt2=`date -Iseconds`
dt1=`date -Iseconds -d '1 minutes ago'`
cred="<TOKEN>"
ztag="<ZONEID>"
wafsrc="firewallCustom"
curl "https://api.cloudflare.com/client/v4/graphql" -H "Authorization: Bearer $cred" -H "Content-Type: application/json" -d '{"query":"{viewer{zones(filter:{zoneTag:\"'$ztag'\"}){firewallEventsAdaptiveByTimeGroups(filter:{source:\"'$wafsrc'\",datetime_geq:\"'$dt1'\",datetime_lt:\"'$dt2'\"},limit:1,orderBy:[datetimeMinute_DESC]){count,dimensions{datetimeMinute}}}}}"}'
{
"data": {
"viewer": {
"zones": [
{
"firewallEventsAdaptiveByTimeGroups": [
{
"count": 98,
"dimensions": {
"datetimeMinute": "2023-08-26T08:32:00Z"
}
}
]
}
]
}
},
"errors": null
}
ログ
firewallEventsAdaptive や fiwall Event ログは Adaptive sampling を採用し、イベント数の増加に応じてサンプリングを利用します。一方、Logpush(Enterpriseプラン)では HTTP リクエストログ は全リクエストをとれるので、そこからロジックを組み立てることもできそうです。
Logpush 自体は new relic、Sumo Logic、Splunk など検索すると SEIM との連携も出てきます。Bigquery での分析など 他にも 外部とのつなぎで独自のエコシステムが作れます。
その他リンク
Cloudflare のイロイロなプロダクトの通知にタグ付けされている Blog
Free プランでのAPI 利用例
GraphQL データセットの一覧の取り方
執筆 BGM
夏も終わりだ。。 🍺
Maysa Leak - Dangerous Summer Night