Web上の攻撃の対象領域が拡大するにつれ、CloudflareのWebアプリケーションファイアウォール(WAF)は、これらの攻撃を軽減する無数のソリューションを提供します。これは、お客様にとっては素晴らしいことですが、弊社が対応する数百万のリクエストのワークロードのカーディナリティにより、誤検知が発生することは避けられません。つまり、お客様向けのデフォルト設定を微調整する必要があるのです。
ファインチューニングは不透明なプロセスではありません。お客様はいくつかのデータポイントを取得してから、何が有効かを決定する必要があります。この記事では、WAFが特定のアクションを実行する理由や、ノイズを減らして信号を増加させるための改善点をお客様が知っていただけるように、Cloudflareが提供するテクノロジーについて説明します。
Logのアクションは素晴らしいです。もっとできることがあると思いますか?
CloudflareのWAFは、アプリケーション層を標的とする攻撃であるさまざまな種類のアプリケーション層攻撃から配信元サーバーを保護します。保護は、次のようなさまざまなツールで提供されます。
これらのツールは、Rulesetsエンジン上に構築されています。ルール式に一致する場合、エンジンはアクションを実行します。
Logアクションは、ルールの動作をシミュレートするために使用されます。このアクションにより、ルール表現がエンジンによって一致したことが証明され、セキュリティ分析、セキュリティイベント、Logpush、またはEdge Log Delivery経由でアクセスできるログイベントが出力されます。
ログは、ルールが一致することが予想されたトラフィックで期待通りに機能することを検証するのには優れているものの、特にルール式が多くのコードパスを取ることができる場合、ルールの一致を示すのは十分ではありません。
擬似コードでは、式は次のようになります:
いずれかのHTTPリクエストヘッダーに「authorization」キーが含まれている場合、またはhttpホストヘッダーの小文字での表現が「cloudflare」で始まる場合、
THENログのルール言語構文は次のようになります:
any(http.request.headers[*] contains "authorization") or starts_with(lower(http.host), "cloudflare")
この表現のデバッグでは、いくつかの問題が発生します。上記のOR式の左側(LHS)と右側(RHS)のどちらが一致するのか?Base64デコーディング、URLデコーディング、そしてこの場合は小文字化などの機能は、これらのフィールドの元の表現に変換を適用することができ、リクエストのどの特性が一致につながったのか、さらに不明確になります。
さらに複雑なことに、1つのルールセット内の多くのルールが一致を登録することが可能です。Cloudflare OWASPのようなルールセットは、異なるルールの累積スコアを使用し、スコアが設定しきい値を超えた時にアクションをトリガーします。
さらに、Cloudflare Managed、OWASPルールの表現はプライベートです。これにより、セキュリティ体制は強化されますが、お客様は、タイトル、タグ、説明から、これらのルールが何をするのかを推測することしかできないということにもなります。例えば、「SonicWall SMA - Remote Code Execution - CVE:CVE-2025-32819」というラベルの付いたものがあります。
疑問が生じる:私のリクエストのどの部分が、ルールセットエンジンでの一致につながりましたか?これは誤検出ですか?
ここで登場するのが悪意のあるペイロードロギングです。これにより、一致につながったルールの特定のフィールドや、Transformations後のそれぞれの値まで掘り下げることができます。
悪意のあるペイロードロギングは、リクエスト内のどのフィールドが、WAFがアクションを実行することにつながったルールに関連付けられているかを記録する機能です。これにより、曖昧さが減り、誤検知の発見、正確性の保証、パフォーマンス向上のためのルールの微調整に役立つ情報が提供されます。
上記の例では、悪意のあるペイロードログエントリーには式のLHSまたはRHSのいずれかが含まれますが、両方は含まれません。
ペイロードロギングとルールセットエンジンはWirefilter上に構築されており、これについては幅広く説明されています。
基本的にこれらのエンジンは、コンパイラートレイトを実装するRustで書かれたオブジェクトです。この特徴は、これらの表現から得られた抽象構文ツリー(AST)のコンパイルを推進します。
struct PayloadLoggingCompiler {
regex_cache HashMap<String, Arc<Regex>>
}
impl wirefilter::Compiler for PayloadLoggingCompiler {
type U = PayloadLoggingUserData
fn compile_logical_expr(&mut self, node: LogicalExpr) -> CompiledExpr<Self::U> {
// ...
let regex = self.regex_cache.entry(regex_pattern)
.or_insert_with(|| Arc::new(regex))
// ...
}
}
ルールセットエンジンは式を実行し、それが true と評価された場合、式とその 実行コンテキスト がペイロード ログ コンパイラに送信され、再評価されます。実行コンテキストは、式を評価するのに必要なすべてのランタイム値を提供します。
再評価が行われると、true と評価された式の支店に関係するフィールドが記録されます。
ログの構造は、wirefilterフィールドとその値のマップです Map<Field, Value>
{
“http.host”: “cloudflare.com”,
“http.method”: “get”,
“http.user_agent”: “mozilla”
}
注:これらのログは、お客様が提供するパブリックキーで暗号化されます。
これらのログは、ロギングパイプラインを通過し、さまざまな方法で読み取ることができます。お客様は、Logpushジョブを構成して、お客様のプライベートキーを使用してこれらのログを自動的に復号化するカスタムWorkerに書き込むことができます。悪意のあるペイロード Logging CLIツール、Worker、またはCloudflareダッシュボードも復号化に使用できます。
Wirefilterでは、一部のフィールドは配列タイプです。フィールドhttp.request.headers.namesは、リクエストのすべてのヘッダー名の配列です。たとえば:
[“content-type”, “content-length”, “authorization”, "host"]
少なくとも1つのヘッダーが「c」という文字を含むため、any(http.request.headers.names[*] contains “c”が含まれる)は、trueと評価されます。以前のバージョンの悪意のあるペイロードロギングコンパイラでは、「http.request.headers.names」のすべてのヘッダーがフィールドは、true と評価する式の一部であるため、ログに記録されます。
悪意のあるペイロードログ(旧)
http.request.headers.names[*] = [“content-type”, “content-length”, “authorization”, "host"]
ここでは、配列フィールドを部分的に評価し、制約式に一致するインデックスをログに記録します。この場合は、"c"を含むヘッダーだけです。
悪意のあるペイロードログ(新規)
http.request.headers.names[0,1] = [“content-type”, “content-length”]
これにより、wirefilterのオペレーターが可能になります。「eq」のような一部の演算子は完全一致になります。例:http.host eq “a.com”.「in」、「contains」、「matches」など、「部分的」一致を実現する他の演算子も正規表現と並行して動作します。
この例の式:`any(http.request.headers[*] contains “c”)` は、部分一致を生成する「contains」演算子を使っています。また、「any」関数を使用していますが、これは部分一致を生成すると言えます。なぜなら、少なくとも1つのヘッダーに「c」が含まれている場合、そのヘッダーをログに記録する必要があるからです。以前のバージョンで行ったように、すべてのヘッダーをログに記録するのではありません。
悪意のあるペイロードロギングコンパイラーの改善により、これらの表現が評価される際に、部分的な一致だけを記録します。この場合、新しいペイロードロギングコンパイラは、Rust標準ライブラリのバイトの「find」メソッドと同様に、「contains」演算子を処理します。これにより、悪意のあるペイロードログが改善されます:
http.request.headers.names[0,1] = [“c”, “c”]
これにより、物事がより明確になりました。また、ロギングパイプラインが数百万バイトを処理するようになるため、節約できます。例えば、よく分析されるフィールドは、リクエスト本文(http.request.body.raw)で、サイズが数十キロバイトになることもあります。表現が、3つの文字と一致する正規表現パターンをチェックしている場合があります。この場合は、キロバイトではなく3バイトをログに記録します。
[c]、[c]は、本当の意味ではありません。一致の正確な理由を提供し、お客様のストレージ宛先に書き込まれるバイト量を大幅に削減できたとしても、主な目的はお客様に有用なデバッグ情報を提供することです。悪意のあるペイロードロギングの改善の一環として、コンパイラーは、部分的な一致の「前」と「後」(該当する場合)もログに記録します。現在、これらのバッファのサイズはそれぞれ15バイトです。つまり、悪意のあるペイロードログは次のようになります:
http.request.headers[0,1] = [
{
before: null, // isnt included in the final log
content: “c”,
after: “ontent-length”
},
{
before: null, // isnt included in the final log
content: “c”,
after:”ontent-type”
}
]
悪意のあるペイロードログの例(旧)
悪意のあるペイロードログ(新規)の例
以前のログでは、すべてのヘッダー値がありました。新しいログでは、HTTPヘッダー内の悪意のあるスクリプトである8番目のインデックスがあります。一致は「<script>」タグ上にあり、残りはグレー色のテキストであるコンテキストです。
マネージドルールは、悪意のあるリクエストのフィンガープリントを生成するために、正規表現に大きく依存しています。こうした表現の解析とコンパイルは、CPU負荷の高いタスクです。マネージドルールは一度記述され、何百万ものゾーンにデプロイされるため、こうした正規表現をコンパイルし、メモリにキャッシュすることで恩恵を受けます。これにより、プロセスが再起動するまで再コンパイルする必要がないため、CPUサイクルが節約されます。
悪意のあるペイロードロギングコンパイラーは、これらのログの中間状態を保存するために、動的にサイズの異なる配列またはベクトルをたくさん使用します。SmallvecのようなCrateは、ヒープ割り当てを減らすためにも使われます。
時折、お客様の悪意のあるペイロードログは「切り捨て」で表示されることがあります。これは、すべてのファイアウォールイベントにバイト単位のサイズ制限があるためです。この制限を超過すると、悪意のあるペイロードログは切り捨てられます。
悪意のあるペイロードログ(旧)
悪意のあるペイロードログ(新規)
悪意のあるペイロードログの50バイトサイズが1.5キロバイトから500バイトに縮小、つまり67%削減されました!つまり、悪意のあるペイロードログの切り捨てがさらに少なくなるのです。
現在、非可逆表現のutf-8文字列を使って値を表しています。つまり、マルチメディアのような無効なutf-8文字列は、U+FFFDユニコード置き換え文字として表されます。バイナリデータで機能するルールの場合、これらの値の整合性はバイト配列、または異なるフォーマットで保持する必要があります。
悪意のあるペイロードロギングのストレージ形式はJSONです。CBOR、Cap'n Proto、Protobufなどの他のバイナリ形式と並んで、これをベンチマークとし、パイプラインでどれだけの処理時間が短縮されるかを確認します。これにより、ログをお客様により速く配信できるようになり、バイナリ形式は後方互換性のある定義されたスキーマを維持するのにも役立つという利点もあります。
最後に、悪意のあるペイロードロギングはマネージドルールでのみ機能します。また、カスタムルール、WAF attack score、コンテンツスキャン、Firewall for AIなど、他のCloudflare WAF製品への展開が予定されています。
Firewall for AIによって検出された個人を特定できる情報を含むプロンプトを示す悪意のあるペイロードロギングの例:
WAFによって実行されるアクションが可視化されることで、ルールや設定が期待する通りのものであることを保証できます。悪意のあるペイロードロギングの特殊性改善は、この方向への一歩です。今後は、信頼性の向上、遅延改善、より多くのWAF製品への拡張が期待されます。
これはJSONスキーマの破壊的な変更であったため、適切なドキュメントを持つお客様に徐々に展開しました。
悪意のあるペイロードロギングを開始し、有効にするには、開発者向けドキュメントをご覧ください。