WordPressのカスタマイズやヘッドレス開発、モダンな管理画面UIの構築において、WordPress REST APIは不可欠な基盤技術です。
しかし、REST APIのエンドポイントを自作(register_rest_route)する際、「認証(Authentication)」と「認可(Authorization)」の設計が不十分なまま公開され、重大な脆弱性(Missing Authorization / 情報漏えい / データの不正改変)を引き起こすケースが後を絶ちません。
💡 本記事は「WordPress セキュアコーディング実践シリーズ」の第2弾です
- 第1弾:WordPressのnonceを理解しセキュアな機能開発へステップアップ(CSRF対策の基礎)
- 第2弾(本記事):WordPress REST APIの認証・権限管理入門(wp_rest_nonce & permission_callback)
- 第3弾:current_user_can()によるWordPress権限チェック実践(認可・Capability設計)
- 第4弾:sanitize_text_fieldとwp_ksesの使い分け完全ガイド(入力無害化・XSS対策)
本記事では、WordPress REST APIにおけるセキュリティの全体像から、Cookie認証時のCSRFを防ぐwp_rest_nonceの正しい受け渡し、そしてエンドポイント保護の要であるpermission_callbackの実践的な実装パターンまで、コード例とともに徹底解説します。
1. REST APIにおける「認証」と「認可」の違い
セキュリティを実装する上で、まず明確に区別しなければならないのが「認証(Authentication)」と「認可(Authorization)」です。
| 区分 | 英語 | 意味・役割 | WordPressでの主な手段 |
|---|---|---|---|
| 認証 | Authentication | 「アクセスしてきたユーザーは誰か」を確認する | Cookie(セッション)、アプリケーションパスワード、JWT等 |
| 認可 | Authorization | 「認証されたユーザーにその操作を行う権限があるか」を確認する | permission_callback、current_user_can()、Capability |
「ログインしていること(認証)」を確認しただけでは不十分です。一般購読者(Subscriber)のアカウントでログインしたユーザーが、管理者権限の設定変更APIを叩けてしまう状態は典型的な「認可不備(Missing Authorization)」の脆弱性となります。
2. WordPress REST APIの認証方式
WordPress REST APIでは、リクエストの送信元環境に応じて主に3つの認証アプローチが存在します。
① Cookie認証(同一サイト内のブラウザ通信)
WordPressの管理画面内スクリプトや、フロントエンドでログイン中ユーザーに操作を行わせる場合に使用されます。ブラウザが自動的にWordPressのログインCookieを送信しますが、CSRF攻撃を防ぐためにwp_rest_nonce(X-WP-Nonceヘッダー)の併用が必須となります。
② アプリケーションパスワード(外部システム・スクリプト連携)
WordPress 5.6から標準搭載された機能で、ユーザープロフィール画面から生成できる専用パスワードです。Basic認証ヘッダーにユーザー名とアプリケーションパスワードを載せて通信します。管理者のメインパスワードを外部に晒すことなく、安全に外部連携が可能です。
③ JWT / OAuthトークン認証(SPA・モバイルアプリ)
Next.jsやReact、モバイルアプリなどの完全分離型フロントエンドからAPIを呼び出す場合、JWT(JSON Web Token)プラグイン等を利用してステートレスにBearerトークンで認証を行います。
3. wp_rest_nonce(X-WP-Nonce)の仕組みと実装手順
同一ドメインからのAjax/RESTリクエストでCookie認証を利用する場合、CSRF対策としてwp_create_nonce('wp_rest')で生成したnonceを送信する必要があります。
通常のAjax通信で使うcheck_ajax_referer()とは異なり、REST APIではアクション名を必ず 'wp_rest' で固定して生成するのがWordPressの仕様です。
Step 1: PHP側でフロントエンドにnonceとエンドポイントを渡す
wp_enqueue_scripts または admin_enqueue_scripts でスクリプトを読み込む際に、wp_localize_script() を使ってnonceをJavaScript側に安全に渡します。
<?php
// functions.php またはプラグインファイル
add_action('wp_enqueue_scripts', 'my_enqueue_custom_scripts');
function my_enqueue_custom_scripts() {
wp_enqueue_script(
'my-custom-api-script',
get_template_directory_uri() . '/js/api-client.js',
array('jquery'),
'1.0.0',
true
);
// REST APIのベースURLと専用nonceをJSグローバル変数として渡す
wp_localize_script('my-custom-api-script', 'MyApiSettings', array(
'root' => esc_url_raw(rest_url()),
'nonce' => wp_create_nonce('wp_rest'), // 必ず 'wp_rest' を指定
));
}
Step 2: JavaScript側で X-WP-Nonce ヘッダーを付与してリクエスト送信
モダンな fetch API または axios を使用して、リクエストヘッダーの X-WP-Nonce にnonceを設定します。
// api-client.js
async function updateUserData(userId, payload) {
try {
const response = await fetch(`${MyApiSettings.root}my-plugin/v1/users/${userId}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-WP-Nonce': MyApiSettings.nonce // X-WP-Nonceヘッダーに設定
},
body: JSON.stringify(payload)
});
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.message || 'APIリクエストに失敗しました');
}
const data = await response.json();
console.log('更新成功:', data);
return data;
} catch (error) {
console.error('エラー:', error);
alert(error.message);
}
}
WordPressコアは、X-WP-Nonce ヘッダーが存在する場合、自動的に wp_verify_nonce($nonce, 'wp_rest') を実行して現在のログインユーザーとしてリクエストを認証します。
4. permission_callback による厳格な認可チェック
エンドポイントを登録する register_rest_route() において、最も重要なセキュリティ設定が permission_callback です。
【危険】permission_callback の省略や誤用
WordPress 5.5以降、permission_callback を省略すると開発用通知(_doing_it_wrong)が出力されます。また、警告を消すためだけに 'permission_callback' => '__return_true' を安易に設定してしまうと、誰でもアクセス可能な全公開APIになってしまいます。
正しい実装パターン:current_user_can() と WP_Error の連携
permission_callback にはコールバック関数(クロージャまたは関数名)を指定し、アクセス可否を true または WP_Error で返却します。WP_Error を返すと、適切なHTTPステータスコード(401 Unauthorized / 403 Forbidden)とともにJSONエラーがクライアントに返却されます。
<?php
add_action('rest_api_init', 'my_register_custom_rest_routes');
function my_register_custom_rest_routes() {
register_rest_route('my-plugin/v1', '/settings', array(
'methods' => WP_REST_Server::EDITABLE, // POST, PUT, PATCH
'callback' => 'my_update_plugin_settings',
'permission_callback' => function (WP_REST_Request $request) {
// 1. ログイン状態の確認
if (!is_user_logged_in()) {
return new WP_Error(
'rest_not_logged_in',
'この操作を行うにはログインが必要です。',
array('status' => 401)
);
}
// 2. 権限(Capability)の確認
if (!current_user_can('manage_options')) {
return new WP_Error(
'rest_forbidden',
'この設定を変更する権限がありません。',
array('status' => 403)
);
}
return true;
},
'args' => array(
'site_notice' => array(
'required' => true,
'type' => 'string',
'validate_callback' => function($param) {
return is_string($param);
},
'sanitize_callback' => 'sanitize_text_field',
),
),
));
}
5. パラメータのバリデーションとサニタイズ(args定義)
エンドポイントのセキュリティは権限チェックだけでは完結しません。送信されてきたパラメータの検証(Validation)と無害化(Sanitization)を args 内で宣言的に定義します。
| コールバック | 役割 | 動作 |
|---|---|---|
validate_callback | 入力値の妥当性検証 | 期待する型やフォーマットかを判定(true/false または WP_Errorを返却) |
sanitize_callback | 入力値の無害化 | HTMLタグ除去や型キャストを実施(sanitize_text_field, absint 等) |
適切なサニタイズ関数の選択については、シリーズ記事「sanitize_text_fieldとwp_ksesの使い分け完全ガイド」で詳しく解説しています。
6. REST API開発におけるセキュリティチェックリスト
- エンドポイント登録時:すべての
register_rest_routeに適切なpermission_callbackを定義しているか? - 権限の厳格化:
current_user_can('manage_options')や対象リソースに応じたメタCapability(edit_post)で認可しているか? - CSRF対策:Cookie認証を利用するブラウザ通信で
X-WP-Nonce(wp_restnonce)を送信・検証しているか? - 入力保護:
args定義内でvalidate_callbackとsanitize_callbackを必ず指定しているか? - レスポンス安全性:権限エラー時に詳細な内部スタックトレースやDB情報を返却せず、適切なHTTPステータス(401/403)を返しているか?
7. まとめ&セキュアコーディングシリーズ関連記事
WordPress REST APIは柔軟で強力な機能ですが、エンドポイントの公開範囲や認可チェックが少しでも甘いと、不正アクセスやデータ改ざんの格好の標的になります。
「認証(Authentication)」と「認可(Authorization)」を正しく分離し、wp_rest_nonce と permission_callback を確実に実装することが、堅牢なWordPress開発の第一歩です。
📚 開発者向けセキュアコーディング関連記事
- 【シリーズ第1弾】WordPressのnonceを理解しセキュアな機能開発へステップアップ – [CVE-2025-1463]脆弱性解説
フォーム・リンク・AjaxにおけるCSRF防御の基礎と実装手法を解説。 - 【シリーズ第3弾】current_user_can()によるWordPress権限チェック実践|脆弱性を防ぐ認可・Capability設計
is_admin()の落とし穴からメタCapabilityを活用した個別リソース認可まで徹底解説。 - 【シリーズ第4弾】sanitize_text_fieldとwp_ksesの使い分け完全ガイド|WordPress入力無害化とXSS対策
プレーンテキストとリッチHTMLの無害化手法、出力エスケープとの組み合わせ方を整理。
🛡️ あなたのWordPressサイトの安全性をチェックしませんか?
プラグインの脆弱性や設定ミス、セキュリティリスクは目に見えない場所で発生します。「MozCheck」は、WordPressサイトのURLを入力するだけで、セキュリティ状態や改善ポイントを即座に診断できる無料ツールです。
コメントを残す