ConoHa WINGでWordPressのREST APIが403「閲覧できません」になる原因はWAFだった

ConoHa WINGのWAFがWordPress REST APIのリクエストをブロックする様子のイメージ 記事一覧

WordPressのREST APIを使って記事を自動投稿する仕組みを作っていたときのことです。前日まで問題なく動いていたのに、翌日いきなり 403エラー で投稿できなくなりました。

結論から言うと、ConoHa WING の WAF(Web Application Firewall)が 403 を返していたのが原因でした。自分の書いた記事が「SQLインジェクション攻撃」と誤検知されていたのです。同じ症状で悩む人のために、切り分けの手順から解決までを実際のログ付きで残しておきます。

※ ConoHa WING自体の基本的な使い方は「ConoHa WINGの使い方ガイド【初心者向け】」にまとめています。

症状:REST APIへの投稿が403で弾かれる

出ていたエラーはこれです。

投稿API失敗 HTTP 403: <HTML><HEAD><TITLE>閲覧できません (Forbidden access)</TITLE></HEAD>...

厄介なのは前日は同じコードで成功していたことです。認証情報(アプリケーションパスワード)も変えていない。コードも変えていない。それなのに翌日だけ弾かれる。

最大のヒント:WordPressの403か、サーバーの403か

ここが今回いちばん重要な切り分けです。私は最初「WordPress側の権限エラーかな」と疑いましたが、それは違うとすぐ分かりました。理由はこうです。

  • WordPressが返す403 … JSONが返ってくる(例: {"code":"rest_cannot_create", ...}
  • 今回返ってきたもの … 日本語のHTMLエラーページ

WordPress REST API は本来JSONを返すエンドポイントです。そこからHTMLのエラーページが返ってきた時点で、リクエストはWordPressに届いていないと判断できます。つまりサーバーの手前で弾かれている=WAFやサーバー設定の仕業です。

この見分けを知らないと、WordPressの権限設定やプラグインを延々と疑って時間を溶かします。返ってきたのがJSONかHTMLかを見る。これだけで捜査範囲が一気に絞れます。

犯人を特定する:ConoHa WINGのWAFログを見る

ConoHa WINGにはWAFのログが残っており、コントロールパネルから確認できます。

  1. ConoHaコントロールパネルにログイン
  2. 上部メニュー 「WING」 → 左メニュー 「サイト管理」
  3. 「サイト セキュリティ」 → 「WAF」 → 「ログ」

エラーが出た時刻のログを探すと、こう記録されていました。

  • 日時:20:52:55(投稿が失敗した時刻とピッタリ一致)
  • 攻撃ターゲットURL/wp-json/wp/v2/...(=WordPressのREST API)
  • 攻撃元IPアドレス:自宅の回線のIP
  • 攻撃内容SQLインジェクションからの防御22(and/or, </>)

自分の家から自分のブログへ送った投稿が、「SQLインジェクション攻撃」として記録されていました

なぜ誤検知するのか

引っかかったルール名に答えが書いてあります。「and/or, </>」です。このルールはざっくり言うと、

  • and や or という単語
  • </> のようなHTMLタグ的な文字列

が同時に含まれるリクエストを「SQLインジェクションの疑いあり」と判定します。ところが、WordPressの記事本文はHTMLの塊です。<p> や </h2> は当たり前に入りますし、英単語の and / or も普通に混じります。

つまり正当な記事投稿が、構造的にこのルールを踏み抜くのです。前日は通って翌日は弾かれたのも、これで説明がつきます。その日の記事本文にたまたま条件が揃ったかどうかで結果が変わる。だから再現性がなく、原因が分かりにくいのです。

解決:該当ルールを「除外」する

WAFログの各行の左端に 「除外」 ボタンがあります。これを押すだけで、そのルールによるブロックが除外され、投稿が通るようになります。実際、除外した直後に再実行したところ、あっさり成功しました。

注意:WAFを丸ごとOFFにしてはいけない

手っ取り早く「WAFを無効化」したくなりますが、それはやめたほうがいいです。WAFはWordPressを狙う攻撃を実際に止めてくれています。今回やるべきはピンポイントの除外だけです。

「SQLインジェクション対策のルールを外して大丈夫なのか」と不安になるかもしれません。私はこう整理して納得しました。

  • 対象は /wp-json/ という認証が必要なエンドポイント。アプリケーションパスワードがなければそもそも叩けない
  • WordPress自身がREST APIの入力を検証し、データベース操作では値を直接SQLに埋め込まない作りになっている
  • 今回のルールは誤検知が多い広すぎるヒューリスティックで、放置すると自分の投稿が永久に通らない

とはいえ、防御が一枚薄くなるのは事実です。だからこそ「全体OFF」ではなく「このルール・このURLだけ除外」に留めるのが肝心です。WAF以外の守りも合わせて固めておきたい方は「WordPress初心者がやっておくべきセキュリティ対策」も参考にしてください。

再発ポイント:他のエンドポイントでも起こる

WordPressのREST APIは投稿だけではありません。画像をアップロードすれば /wp-json/wp/v2/media、タグを作れば /wp-json/wp/v2/tags を叩きます。これらが別途ブロックされる可能性があります。

また403が出たら、同じようにWAFログを見て、同じように除外すれば大丈夫です。「403+HTMLのエラーページならWAFを疑う」と覚えておけば、次は5分で解決できます。

まとめ

  • REST APIで 403「閲覧できません (Forbidden access)」 が出たら、まず返ってきたのがJSONかHTMLかを見る。HTMLならWordPressではなくサーバー手前(WAF)が犯人
  • ConoHa WINGなら サイト管理 → サイト セキュリティ → WAF → ログ で犯人を特定できる
  • 今回の犯人は 「SQLインジェクションからの防御22(and/or, </>)」。記事本文のHTMLタグと and/or に反応する誤検知
  • 対処は該当ログの 「除外」WAF全体をOFFにしない
  • media や tags のエンドポイントでも再発しうる

エラーメッセージが日本語で「閲覧できません」と出るせいで、レンタルサーバーの制限なのかWordPressの不具合なのか分かりにくい問題でした。同じところで止まっている方の役に立てば幸いです。

コメント

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