WordPress を更新した後に、管理画面の保存、プラグイン更新、REST API、Gutenberg の操作が WAF / ModSecurity に止められることがあります。画面上では保存エラーや JSON レスポンスエラーに見えても、実際には WAF がリクエスト本文を攻撃パターンとして判定している場合があります。
この記事では、WordPress 更新後に ModSecurity が反応する理由と、例外をどのように狭く作るべきかを整理します。単に WAF を止めるのではなく、何がどのルールに反応したのかを見て、運用可能な形に調整するのが目的です。
発生すること
WordPress 更新後の WAF 反応は、次のような症状として見えます。
- ブロックエディタで記事を保存できない
- REST API が 403 になる
- プラグイン更新や設定保存が失敗する
- 管理画面上では JSON レスポンスエラーに見える
- 本文内のコード、URL、HTML、SQL 風文字列にだけ反応する
WordPress 側の画面だけを見ると原因が分かりにくいですが、WAF の audit log を見ると、どのルールがどのパラメータに反応したのかを確認できます。
誤検知という表現への違和感
WAF の反応をすぐに「誤検知」と呼ぶのは、少し雑です。WAF はリクエスト本文に含まれるパターンを見て判定しているため、技術記事のコードブロックやコマンド例が攻撃パターンに似ていれば、ルールとしては反応します。
問題は、反応したこと自体よりも、その反応をどう運用に落とすかです。WordPress の正当な操作を止め続けるなら調整が必要ですが、だからといって WAF 全体を無効化すると、本来守りたい範囲まで失います。
WAF 判定の 4 分類
WAF のログを見る時は、反応を大きく 4 つに分けると整理しやすくなります。
| 分類 | 内容 | 対応 |
|---|---|---|
| 正しい検知 | 実際に攻撃や不正アクセスを止めている | 遮断を維持する |
| 許容できる検知 | 管理者操作だが頻度が低く、手動許可でよい | 都度確認する |
| 調整すべき検知 | 正当な WordPress 操作を継続的に止める | 狭い例外を作る |
| 過剰な除外 | 広く除外しすぎて保護が弱くなる | 例外範囲を見直す |
WordPress 更新後に反応しやすい理由
WordPress 更新後は、REST API の使われ方、Gutenberg の保存内容、プラグインのリクエスト形式、管理画面の JavaScript の挙動が変わることがあります。結果として、以前は通っていたリクエストが WAF ルールに当たるようになることがあります。
- Gutenberg が記事本文を REST API で送る
- コードブロックや HTML ブロックがリクエスト本文に入る
- プラグイン設定に URL、正規表現、SQL 風の文字列が入る
- REST API の endpoint や request body が更新で変わる
- OWASP CRS の更新で判定が厳しくなる
特に技術ブログでは、記事本文にシェルコマンド、設定ファイル、SQL、HTML、HTTP ヘッダーが含まれるため、一般的なブログより WAF に反応しやすい面があります。
まず audit log を確認する
最初に見るべきなのは audit log です。エラー画面や WordPress の通知だけでは、どのルールが原因か分かりません。
コマンド
grep -i "Access denied" /var/log/apache2/modsec_audit.log
grep -i "wp-json" /var/log/apache2/modsec_audit.log
grep -i "id \" /var/log/apache2/modsec_audit.log確認したいのは、少なくとも rule id、request URI、matched variable、matched data です。これが分からない状態で例外を作ると、範囲が広くなりすぎます。
見るべき項目
| 項目 | 見る理由 |
|---|---|
| Rule ID | どの WAF ルールが反応したかを特定する |
| Request URI | 管理画面、REST API、特定プラグインのどこで起きたかを見る |
| Matched Variable | 本文、ヘッダー、Cookie、引数のどこに反応したかを見る |
| Matched Data | どの文字列が攻撃パターンに見えたかを見る |
| Client IP / User | 管理者操作か外部アクセスかを切り分ける |
たとえば REST API の投稿保存で、記事本文の一部にだけ反応しているなら、REST API 全体を除外するのではなく、そのルールと対象変数に絞って調整するのが基本です。
例外は狭く作る
WAF の例外は、できるだけ狭く作ります。広い例外は一時的には楽ですが、後から何を守っているのか分からなくなります。
| 避けたい例外 | 望ましい例外 |
|---|---|
| WordPress 全体を WAF から除外する | 管理画面や REST API の必要な endpoint に限定する |
| すべての CRS ルールを無効化する | 反応した rule id に限定する |
| すべての request body を除外する | 対象パラメータや matched variable に限定する |
| 恒久例外をすぐ入れる | 一時的に観察してから恒久化する |
例外の考え方
<LocationMatch "^/wp-json/wp/v2/posts">
SecRuleRemoveById 942140
</LocationMatch>上記は考え方の例です。実際には、audit log で確認した rule id、対象 URI、対象変数に合わせて調整します。ルール ID だけを見て機械的に除外するのではなく、何に反応しているのかを確認してから適用します。
DetectionOnly で観察する選択肢
本番でいきなり遮断するのが難しい場合は、一時的に DetectionOnly で観察する選択肢もあります。これは検知ログを取りながら遮断しないモードです。
ただし、DetectionOnly は恒久運用の逃げ道ではありません。どのルールがどの正常操作に反応するかを把握し、必要な例外を作るための観察期間として使うのが自然です。
キャッシュや CDN も疑う
WAF 以外にも、リバースプロキシ、キャッシュ、CDN がエラー応答を返していることがあります。WordPress から見ると同じ保存失敗でも、実際には前段のキャッシュやプロキシが POST リクエストを正しく扱っていない場合があります。
- REST API の POST がキャッシュ対象になっていないか
- Cookie や Authorization ヘッダーが前段で落ちていないか
- キャッシュされた 403 や 500 が返っていないか
- WAF とキャッシュのどちらが先に応答しているか
参考書籍
書籍
ModSecurity / WAF のルール、検知、例外設計を深く確認したい場合の参考書籍です。
Amazon で見るこのリンクは Amazon アソシエイトリンクです。
関連する記事
Gutenberg 保存時の JSON エラーを、REST API、WAF、PHP、パーマリンクの層で確認する記事です。
Apache と ModSecurity / OWASP CRS を使う場合の基本設定です。
WordPress の外部通信を、Pod、Node、DNS、Proxy、Firewall の層で確認する記事です。
まとめ
WordPress 更新後に ModSecurity が反応する場合、まず audit log を確認し、rule id、request URI、matched variable、matched data を見ることが重要です。画面上のエラーだけでは、WAF が原因なのか、PHP やリバースプロキシが原因なのか分かりません。
WAF の反応を単に誤検知として扱うのではなく、正当な管理操作を止めているのか、実際に危険な通信を止めているのかを分けて考えます。
例外はできるだけ狭く作り、WordPress 全体や REST API 全体を広く除外しないことが大切です。WAF を止めるのではなく、WordPress の運用に合わせて検知を調整する。この考え方が、長期運用では一番安全です。


