WordPress REST APIの認証・権限管理入門|wp_rest_nonceとpermission_callbackの実践実装

WordPressのカスタマイズやヘッドレス開発、モダンな管理画面UIの構築において、WordPress REST APIは不可欠な基盤技術です。

しかし、REST APIのエンドポイントを自作(register_rest_route)する際、「認証(Authentication)」と「認可(Authorization)」の設計が不十分なまま公開され、重大な脆弱性(Missing Authorization / 情報漏えい / データの不正改変)を引き起こすケースが後を絶ちません。

💡 本記事は「WordPress セキュアコーディング実践シリーズ」の第2弾です

本記事では、WordPress REST APIにおけるセキュリティの全体像から、Cookie認証時のCSRFを防ぐwp_rest_nonceの正しい受け渡し、そしてエンドポイント保護の要であるpermission_callbackの実践的な実装パターンまで、コード例とともに徹底解説します。


1. REST APIにおける「認証」と「認可」の違い

セキュリティを実装する上で、まず明確に区別しなければならないのが「認証(Authentication)」「認可(Authorization)」です。

区分英語意味・役割WordPressでの主な手段
認証Authentication「アクセスしてきたユーザーは誰か」を確認するCookie(セッション)、アプリケーションパスワード、JWT等
認可Authorization「認証されたユーザーにその操作を行う権限があるか」を確認するpermission_callbackcurrent_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開発におけるセキュリティチェックリスト

  1. エンドポイント登録時:すべての register_rest_route に適切な permission_callback を定義しているか?
  2. 権限の厳格化current_user_can('manage_options') や対象リソースに応じたメタCapability(edit_post)で認可しているか?
  3. CSRF対策:Cookie認証を利用するブラウザ通信で X-WP-Noncewp_rest nonce)を送信・検証しているか?
  4. 入力保護args 定義内で validate_callbacksanitize_callback を必ず指定しているか?
  5. レスポンス安全性:権限エラー時に詳細な内部スタックトレースやDB情報を返却せず、適切なHTTPステータス(401/403)を返しているか?

7. まとめ&セキュアコーディングシリーズ関連記事

WordPress REST APIは柔軟で強力な機能ですが、エンドポイントの公開範囲や認可チェックが少しでも甘いと、不正アクセスやデータ改ざんの格好の標的になります。

「認証(Authentication)」と「認可(Authorization)」を正しく分離し、wp_rest_noncepermission_callback を確実に実装することが、堅牢なWordPress開発の第一歩です。

📚 開発者向けセキュアコーディング関連記事

🛡️ あなたのWordPressサイトの安全性をチェックしませんか?

プラグインの脆弱性や設定ミス、セキュリティリスクは目に見えない場所で発生します。「MozCheck」は、WordPressサイトのURLを入力するだけで、セキュリティ状態や改善ポイントを即座に診断できる無料ツールです。

投稿者

🧰 WordPress無料診断

サイト改善の第一歩をお届け

当サイト「MozCheck」は、WordPressサイトの不安をチェックできる無料診断サービスです。
URLを入力するだけ。登録不要、すぐに診断結果が表示されます。

コメント

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です