AWS WAFv2 においてマネージドルールを使いたいのだけれども特定の URL だけに適用してスコープを狭くしたい場合というのはよくあると思います。今回はその方法をまとめます。
環境
今回は WordPress の標準画像アップロード機能での例を挙げます。まず2つのマネージドルールが今回 WordPress の画像アップロード時に障壁となりました。つまり、誤検知で画像アップロードの処理を WAFv2のルールがブロックしてしまうという状況です。こういった例は他のウェブアプリケーションでも起こります。WordPress でもウェブアプリケーションでも基本の考え方は同じです
マネージドルールとは
WAFv2 のマネージドルールは、AWS であらかじめ設定してくれているルールです。例えば WordPress によくある脆弱性とそのパターンをまとめてくれている AWSManagedRulesWordPressRuleSet というものがあります。
今回はこういったマネージドルールのなかから以下のルールを特定の URL にだけ適用する方法を紹介します。
- SizeRestrictions_BODY
- CrossSiteScripting_BODY
ブロックしていたマネージドルール
今回の WordPress 画像アップロード時には AWS-AWSManagedRulesCommonRuleSet というマネージドルールセットの中の SizeRestrictions_BODY と CrossSiteScripting_BODY という 2 つのルールがブロックしていました。これらを特定の URL にだけ適用する方法を紹介します。
ブロックしていたマネージドルールを調査、特定する方法は最後に記載しています。
前提
AWS-AWSManagedRulesCommonRuleSet というルールセットを使用した Web ACLs(保護パック)があることを前提にそれを編集する形で進めます。
今回の具体的な要件
ある特定の URL へのリクエストのみ該当のマネージドルールを Count 処理(通信を通した数を記録する)し、他の URL へのリクエストは Block 処理(通信を遮断する。私の場合ではCloudFrontから403が返ってくる形になっていました)をしたい。
ルールの適用方法概要
ざっくりとどのような仕組みでスコープを絞るのか整理します。
今回の要件を前提としてマネージドルールを直接編集して絞るという設定はできないようです。これは運用を考えても納得がいく仕様だと思います。マネージドルールの条件を直接的に編集できてしまったら、後からどんどんルールが追加された時に混乱することは用意に予想できます。
したがって、以下のように2段階で設定を進めていきます。
- まずは設定を適用したいルールを次のように設定します。
処理を「Override to Count」に設定します。 - オリジナルのカスタムルールを設定します。ここでラベルのルールを指定して特定の URL 以外の処理を「Block」に設定します。
このように 2 段階で設定することでマネージドルールの基本的な仕様部分は変更せず疎結合に新たな設定を加えることができます。
マネージドルールとカスタムルールの設定
ここでは具体的に v2 のコンソールから設定を進めてみます。
2 つのルールアクションを Count に設定する
-
v2 コンソールにアクセスします。https://console.aws.amazon.com/wafv2/homev2
-
左メニューから「Web ACLs」をクリックします。
-
Web ACLs セクションの上部にリージョンを選択するプルダウンがありますので設定してあるリージョンを選択します。私の場合は CloudFront で使用していたので「Global(CloudFront)」を選択しました。
-
設定した Web ACLs が表示されるので「Name」をクリックします。
-
次の画面で「Rules タブ」をクリックします。
-
ここで「Name」に AWS-AWSManagedRulesCommonRuleSet というものが設定してある(前提)のでクリックします。
-
次の画面で右上に「Edit」というボタンがあるのでクリックします。
-
この画面でルールセットに設定されているルールの一覧が表示されます。「SizeRestrictions_BODY」と「CrossSiteScripting_BODY」のプルダウンで「Override to Count」に設定して「Save rule」をクリックします。
オリジナルのカスタムルールを作成
- v2 コンソールにアクセスします。https://console.aws.amazon.com/wafv2/homev2
- 左メニューから「Web ACLs」をクリックします。
- Web ACLs セクションの上部にリージョンを選択するプルダウンがありますので設定してあるリージョンを選択します。私の場合は CloudFront で使用していたので「Global(CloudFront)」を選択しました。
- 設定した Web ACLs が表示されるので「Name」をクリックします。
- 次の画面で「Rules タブ」をクリックします。
- 右上に「Add rules」というプルダウンがあるので「Add my own rules and rule groups」を選択します。
- この画面では詳細を設定していきますが、書いていない項目はデフォルトで進めてみてください。少し長いのでセクションごとに項番を進めていきます。
「Rule type」セクションで「Rule builder」を選択します。 - 「Rule」セクションで任意の「Name」を入力します。
- 「If a request」プルダウンで「matches all the statements(AND)」を選択します。
- 「Statement 1」セクションで「Inspect」を「Has a label」に設定
「Match key」を「awswaf:managed:aws:core-rule-set:SizeRestrictions_Body」に設定します。 - 「Statement 2」セクションで「Negate statement results」にチェックを入れます。
「Inspect」を「URI path」
「Mtach type」を「Starts with string」
「String to match」を「/wp-admin/admin-ajax.php」に設定します。
この URI はウェブアプリケーションであれば画像アップロードなどのエンドポイントになる URI を設定します。 - 「Add another statement」をクリックして「Statement 3」を追加します。
- 「Statement 3」セクションで「Negate statement results」にチェックを入れます。「Inspect」を「URI path」に
「Mtach type」を「Starts with string」
「String to match」を「/wp-json/wp/v2/media」に設定します。
この URI はウェブアプリケーションであれば画像アップロードなどのエンドポイントになる URI を設定します。 - 「Action」セクションの「Action」を「Block」に設定します。
- 「Add rule」ボタンをクリックします。
これでオリジナルのルールが作成できました。ここで設定した内容としては次のようになります。
まずActionをBlockにすることで一旦基本の動作を「通信を遮断する」と設定しています。
その上で指定した2つのURL「/wp-json/wp/v2/media」と「/wp-admin/admin-ajax.php」の文字列がパスの最初にあれば通信を許可するという動きになります。
もう一つのルールを適用して動作確認
CrossSiteScripting_BODY に関しても同様に設定(オリジナルのカスタムルールを作成手順 10 を awswaf:managed:aws:core-rule-set:CrossSiteScripting_Body に変更するだけ)すると無事に WordPress のアップロード機能が動作しました。
ブロックしていたマネージドルールを特定する方法
- AWS WAF v2 の新しいコンソールではない旧コンソールにアクセスします。
- 左のメニューから「Web ACLs」をクリックします。
- 設定した Web ACL の Name をクリックします。
- 開いたページの上部に「Sampled requests」というタブがあるのでそれをクリックします。
- するとページ下部に URI ごとのリクエストが表示されます。この Action の項目が ALLOW のものは通信が許可されているという状態です。逆に BLOCK となっているものは通信が遮断されています。
さらに Sampled requests というセクションの上部プルダウンで Web ACLs で設定したルールごとに絞り込むことができます。これを活用することでどのルールが通信をブロックしているのかがわかります。
JSON でしかできない指定もある
今回は基本的にコンソールから画面を操作して設定を進めてきました。ただ少し複雑な指定をしようとするとできないこともあります。
ただ JSON ではいけるようです。コンソールの編集画面にも以下の説明が書かれています。
You can use the JSON editor for complex statement nesting, for example to nest two OR statements inside an AND statement. The visual editor handles one level of nesting. For web ACLs and rule groups with complex nesting, the visual editor is disabled.
JSONエディタを使用すると、複雑な文のネストが可能です。例えば、AND文の中に2つのOR文をネストできます。ビジュアルエディタは1レベルのネストを処理します。複雑なネストを持つWeb ACLおよびルールグループでは、ビジュアルエディタは無効になります。
自分は今回この例に遭遇することができたのでここに記録しておきます。
URL とクエリの And 条件
example.php?query=true
このように URL 部分とクエリ部分が両方当てはまったら適用するというルールを指定する場合に 2025 年 12 月現在 JSON でないと指定ができないようでした。
私のケースでは以下のように指定することで想定する動作を実現することができました。
{
"NotStatement": {
"Statement": {
"AndStatement": {
"Statements": [
{
"ByteMatchStatement": {
"FieldToMatch": {
"UriPath": {}
},
"PositionalConstraint": "STARTS_WITH",
"SearchString": "example.php",
"TextTransformations": [
{
"Type": "NONE",
"Priority": 0
}
]
}
},
{
"ByteMatchStatement": {
"FieldToMatch": {
"SingleQueryArgument": {
"Name": "query"
}
},
"PositionalConstraint": "EXACTLY",
"SearchString": "true",
"TextTransformations": [
{
"Type": "NONE",
"Priority": 0
}
]
}
}
]
}
}
}
}
あとがき
今回調査を進める中で様々な記事をみたのですが、WordPress 以外でもウェブアプリケーションでは少なからず今回のようなジレンマが発生していました。どこで線引きをするかはある程度目星をつけつつも、状況の変化には対応できるように設計するのが改めて大事だと感じた次第です。