WordPress でコード記事を更新したら 501 Not Implemented|Xserver の WAF 誤検知を切り分けて、MarsEdit で逃がした記録

特定のWordPress記事だけ「501 Not Implemented」になった話|Xserver WAFの誤検知とMarsEditで抜けた経緯 WordPress
この記事は約7分で読めます。

WordPress でコード入りの記事を更新した瞬間に、501 Not Implemented が出たことはありますか。私はあります。ブログ全体が落ちたわけでも、WordPress が壊れたわけでもなく、コードやコマンド例を多く含む特定の記事だけが、更新ボタンを押した瞬間に 501 を返す、という妙な形でした。先に答えを置きます。原因は、Xserver の WAF が、記事本文のコマンドや記号を「攻撃パターンっぽい」と誤検知していたことでした。本文はただの技術解説です。でも WAF は「これはブログの説明文です」という文脈までは読んでくれません。抜け道もありました。MarsEdit(XML-RPC 経由)で送ったら、同じ本文がそのまま通ったのです。

検証環境:WordPress 6.9.4 / Xserver スタンダード / PHP 8.3.21 / MarsEdit 5.3.12(2026年3月)。Xserver の仕様や WAF ルールは変わる可能性があるので、作業時は公式マニュアルとサーバーパネルの表示も確認してください。

技術解説のコードを攻撃と誤検知するWAFの仕組みの図

Xserverで501 Not Implementedエラーが表示された画面

何が起きていたのか

症状は、ぱっと見では掴みにくいものでした。管理画面には入れる。編集画面も開く。本文も入力できる。でも、更新ボタンを押した瞬間に 501。プラグインの保存も設定変更もできるのに、特定の記事の更新だけがダメ。しかも全記事ではなく、コマンド例や設定ファイル名、PHP コードを多く含む記事だけが失敗する。ここまで偏ると、WordPress 全体ではなく、送っている本文の中身そのものが、どこかで止められていると考えるしかありません。HTTP の 501 は本来、サーバーが認識できないリクエストメソッドを受け取ったときなどに使われます。でもこちらは管理画面から普通に更新しているだけ。変なリクエストを送ったと考えるより、途中のセキュリティ判定で止められた線を疑うほうが、状況的には自然でした。

WAF だと、どう絞り込んだか

正直、最初から WAF と分かったわけではありません。いつもの順で疑いました。WordPress 本体を最新に。プラグインを順番に無効化。別のブラウザ、シークレットウィンドウ、別の端末。どれも症状は変わらず、同じ記事で同じ 501 が返る。ここでようやく、クライアント側ではなくサーバー側で何かが止めている、と絞れました。WAF を疑ってから、いきなり全部 OFF にするのは怖かったので、小さく3つ実験しました。

  • コードをほぼ含まない別記事を更新 → 問題なく通る(全体は壊れていない)。
  • 問題の記事から、コードブロックやコマンド例を一時的に削って更新 → 通る場合がある(本文のどこかに WAF が反応している)。
  • サーバーパネルで コマンド対策だけを一時的に OFF にして、元の記事を更新 → 通った。

少なくともこのケースでは、WAF のコマンド対策が反応していた可能性が高い、というところまで絞れました。

3つの切り分け実験からコマンド対策の誤検知に絞り込む図

なぜ技術記事は引っかかるのか

Xserver の WAF には、XSS 対策、SQL 対策、ファイル対策、メール対策、コマンド対策、PHP 対策などの項目があります。技術記事では、これらが反応しそうな文字列を普通に使います。攻撃コードを書いているつもりはなくても、WAF から見ると危険な文字列を含む POST に見えることがある。私の体感では、短いコマンド名や記号がまとまって出てくる記事ほど、更新時に引っかかりやすい印象でした。

分類 記事で使いがちで、引っかかりやすい文字列
シェルコマンド cd, ls, rm, mv, cp, curl, wget, ssh
記号 | ; &&(パイプ・セミコロン)
設定ファイル .htaccess, .htpasswd, php.ini, wp-config.php
PHP 関数 exec(), shell_exec(), file_get_contents()
SQL SELECT, INSERT, UPDATE, DELETE, UNION

ただし、これらを使えば必ず 501 になるわけではありません。前後の文字列や送信内容、サーバー側の判定で変わります。

一時 OFF は、どう安全にやるか

WAF を OFF にすれば更新できるとしても、常時 OFF はおすすめしません。WAF はサイトを守る仕組みで、切ったままだと本来止めるべき攻撃も通します。私がやったのは、コマンド対策だけを一時的に OFF にして、反映を待ち、シークレットウィンドウで更新し、通ったらすぐ WAF を ON に戻す、という流れです。全項目をまとめて OFF にはしません。切り分けにならず、防御も広く外れるからです。作業中は、プラグイン操作やテーマ編集を同時にやらない。一度に複数を変えると、あとで何が原因か分からなくなります。なお、WAF 設定は変更してすぐ反映されないことがあるので、直後に「変わらない」と判断せず、少し時間を置いてから確認してください。

MarsEdit なら、なぜ通ったのか

切り分けで原因が絞れたころ、駄目元で、普段から併用している MarsEdit を試しました。本文もサーバーも同じだから結果は変わらないだろう、と内心思っていたのですが、パブリッシュボタンを押したら、そのまま通った。何度試しても、管理画面の更新で 501、MarsEdit で成功。繰り返し再現する以上、通信経路の違いが効いていると認めるしかありませんでした。

踏み込んで推測すると、こうです。管理画面からの更新は、内部的に REST API(あるいは admin-ajax)への POST で、本文は JSON や form-urlencoded で送られます。WAF はこれを通常の Web フォーム送信として、ボディを文字列レベルで検査しやすい。一方 MarsEdit は古くからの xmlrpc.php 経由で、本文は XML でシリアライズされて送られます。同じルールでも、エンコードや経路の差で文字列マッチが効かなかった可能性がある。あくまで私の環境での推測ですが、同じ内容で通る・通らないが分かれた事実から逆算すると、ここに差があったと考えるのが自然でした。技術記事を書く人にとって、投稿経路をもう1本持っておくのは、かなり安心です。

管理画面のREST/admin-ajax(JSON)はWAF検査で詰まり、MarsEditのxmlrpc.php(XML)はすり抜ける経路差の図

ただし、MarsEdit を保険にするなら xmlrpc.php を有効にすることになります。開けっぱなしは不安なので、Xserver の WordPress セキュリティ設定で、XML-RPC アクセス制限とホワイトリストを使い、投稿に使う IP を登録して入口を絞りました。自宅回線でも IP は変わることがあるので、これは投稿場所がある程度固定されている人向けです。アプリケーションパスワードが使えれば、それで接続するのが安全です。

再発を減らす、コードの載せ方

一時 OFF だけだと、似た記事を書くたびに同じ問題が起きます。そこで載せ方を変えました。

  • 長いサンプルコードは、本文に全部貼らず、GitHub Gist やリポジトリに逃がす。要点と変更箇所だけ本文で説明する。
  • 設定例は、画像で全体像を見せ、本文には必要最小限の抜粋だけ載せる(画像だけだとコピーできないので併用)。
  • 破壊的なコマンドは、完成形のまま載せない。ワンライナーは1行ずつ分けて説明する。これは WAF 対策というより、技術ブログとしての責任に近い部分です。

WAF でも MarsEdit でも直らないとき

どちらでも直らないなら、WAF 以外も疑います。まず WordPress の debug.log です。

debug.log に PHP エラーが残っているなら、プラグインやテーマの処理を疑う。エラーが出ていないのに更新時だけ 501 なら、WordPress の内部処理に届く前で止められている可能性が高い。ログに出るか出ないかで、方向が大きく変わります。自分で切り分けても解決できないときは、Xserver サポートへ。そのときは「501 が出ます」だけでなく、発生条件と試したこと(特定記事だけで起きる、コード例を含む、コマンド対策を一時 OFF にすると通った、発生日時)を具体的に書くと、ログを確認してもらいやすく、URI 単位の除外設定の相談もしやすくなります。

次の自分に渡すメモ

未来の自分が同じ 501 にぶつかったときのために、短く残します。順に試せば絞れます。

  • 別の記事は更新できるか。問題の記事からコードを減らすと通るか。
  • WAF のコマンド対策だけを一時的に OFF にすると、挙動が変わるか。変わったら、すぐ ON に戻す。
  • debug.log に PHP エラーが残っていないか(出る→プラグイン/テーマ、出ない→手前で停止)。
  • 詰まったら MarsEdit(XML-RPC)で送ってみる。使うなら IP 制限で入口を絞る。
  • 長いコードは Gist へ。危険なコマンドは完成形にしない。

冒頭の場面に戻ります。コード付きの記事を更新して 501 が出ると、最初はかなり焦ります。でも、特定の記事だけ更新できない、コードを削ると通る、コマンド対策を一時 OFF にすると通る。ここまで揃えば、WAF の誤検知を強く疑ってよい。そして抜け道として、MarsEdit のような XML-RPC 経由の投稿クライアントがある。これを知っているだけで、次にぶつかったときの自分は、だいぶ楽になっています。

関連記事

WordPress
この記事を書いた人
rapls

WordPressのプラグインを作っているフリーランスエンジニアです。Web開発はもう6年以上。WordPress.orgで Rapls AI Chatbot、Thanks Mail for Stripe、Rapls PDF Image Creator の3本を公開し、保守を続けながら、日本語ロケールの翻訳エディター(PTE)も務めています。このブログに書くのは、現場で自分が実際にハマって、調べて、直した話です。

raplsをフォローする
raplsをフォローする

コメント

タイトルとURLをコピーしました