WordPressのREST APIで、記事の取得や更新はできるのに、DELETE(削除)だけが403 Forbiddenになることがあります。この記事では、実際にこの症状を解決したときの手順をもとに、原因の切り分け方をまとめます。
まず確認:403は「誰が」返しているか
最初に見るべきなのは、403のレスポンスの中身です。返してきた相手によって、見た目がはっきり違います。
- WordPressが返している場合:JSONで返ってきます。例:
{"code":"rest_cannot_delete","message":"...","data":{"status":403}}。この場合は権限(ユーザーの役割)や認証の問題です。 - WordPressより手前で止められている場合:HTMLの「Forbidden」のページが返ってきます。WordPressまで届いていないので、セキュリティプラグインのファイアウォールや、サーバーのWAFなどが原因です。
確認には、存在しない記事IDに向けてDELETEを1回だけ送るのが安全です。記事が消える心配がありません。
curl -s -i -u "ユーザー名:アプリケーションパスワード" \
-X DELETE "https://example.com/wp-json/wp/v2/posts/0"
-iを付けると、ステータスコードとヘッダー、本文がまとめて表示されます。Content-Typeがapplication/jsonならWordPressの返事、text/htmlなら手前で止められています。
WordPressまで届いていれば、404(rest_post_invalid_id:無効な投稿ID)が返ります。403で、中身がHTMLなら、手前で止められています。

切り分けの順番
1. セキュリティプラグインのファイアウォール
セキュリティプラグインには、特定のHTTPメソッドをブロックする設定を持つものがあります。管理画面でファイアウォール機能を一時的にオフにして、もう一度テストします。通るようになれば原因はプラグインです。試したら、すぐに設定を元に戻してください。
2. .htaccessに書き込まれたルール
プラグインによっては、ファイアウォールのルールを.htaccessに直接書き込むものがあります。この場合、プラグインの一部の機能をオフにしただけでは、ルールが残ることがあります。.htaccessにメソッドを制限する記述(RewriteCond %{REQUEST_METHOD}など)がないかも確認しましょう。
3. サーバーのWAF
プラグインや.htaccessを確かめても変わらなければ、レンタルサーバーのWAF(Webアプリケーションファイアウォール)を疑います。多くのサーバーでは、コントロールパネルにWAFの検知ログがあります。テストした時刻、URL(/wp-json/wp/v2/posts/...)、自分の接続元IPで探すと、どのルールで止められたかがわかります。
私たちの場合は、DELETEなどのメソッドを拒否するルールに引っかかっていました。
補足:PythonからだとGETでも403になるとき
PythonのrequestsやurllibでREST APIを呼ぶと、curlでは通るのに403になることがあります。ライブラリの標準のUser-Agentが、WAFやセキュリティプラグインにボットと判定されているのが原因です。ブラウザに似たUser-Agentヘッダーを付けると通ることがあります。
直し方:守りは最小限だけゆるめる
原因のルールがわかっても、WAF全体をオフにするのはおすすめしません。サイト全体の守りが弱くなるからです。
- 検知ログから、そのルールだけを除外する
- 除外したら、もう一度ID 0でテストし、
404(WordPressの返事)になることを確かめる - 除外した設定は、いつでも元に戻せるようにメモしておく
ルールを除外しても、REST APIでの削除にはWordPressの認証が必要です。そのため、すぐに誰でも削除できるようになるわけではありません。それでも、アプリケーションパスワードは必要な人だけに発行し、使わなくなったら取り消しておきましょう。
まとめ
- 403のレスポンスがJSONか、HTMLかで、WordPressの問題か、手前で止められているかがわかる
- テストは、存在しない記事ID(0)へのDELETEで安全に行える
- セキュリティプラグイン→.htaccess→サーバーのWAFの順に切り分ける
- 直すときは、原因のルールだけを除外して、守りは最小限だけゆるめる
このトラブルを解決したときの体験は、Grok BotでAI編集部を作ってみたでも紹介しています。

コメント