WordPressサイトのセキュリティを語る上で欠かせない対策の一つがCSRF(クロスサイトリクエストフォージェリ)対策です。CSRF攻撃は、ユーザーが意図しない操作を、そのユーザーの権限で実行させてしまうもので、データの改ざんや削除、不正な投稿といった被害に繋がる可能性があります。このCSRF攻撃を防ぐためにWordPressが提供している強力な仕組みが「Nonce(ノンス)」です。
Nonceは「Number used once」の略で、一度だけ使われる使い捨てのトークン(文字列)を指します。WordPressでは、特定のアクションを実行する際にこのNonceを生成・検証することで、リクエストが正当なものか、意図された操作であるかを確認します。この記事では、Nonceを扱うための主要な関数群をチートシート形式で詳しく解説します。
Nonceの仕組みとCSRF対策における役割
Nonceは、以下の要素を組み合わせて生成される、一時的でユニークな文字列です。
- アクション名: どのような操作に対するNonceかを示す識別子。
- ユーザー情報: ログインしているユーザーに紐づきます(ログアウト状態のユーザーには別の方法で紐づくこともあります)。
- 時間情報: Nonceには有効期限があります(デフォルトでは約24時間)。
ユーザーが何らかの操作(例: 投稿の削除、設定の変更など)を行う際、WordPressはまずその操作に対応するNonceを生成し、フォームの隠しフィールドやURLのパラメータとして埋め込みます。そして、実際に操作のリクエストがサーバーに送られた際、サーバー側でそのNonceが正しいか(アクション名が一致するか、有効期限内か、ユーザーが適切かなど)を検証します。検証に失敗した場合、そのリクエストは不正なものとして拒否されます。
これにより、攻撃者が用意した罠ページなどから、ユーザーの意図しないリクエストが送信されたとしても、正しいNonceが含まれていないため処理が実行されず、CSRF攻撃を防ぐことができます。
主要Nonce関連関数一覧
WordPressでNonceを生成・検証するために使用できる主要な関数を分類しました。各関数の説明の冒頭には、そのセキュリティ上の重要度や利用頻度を星の5段階評価で示しています。星の数の目安は以下の通りです。
★★★★★:ほぼ全ての開発で頻繁に利用され、基本かつ非常に重要なパラメータ
★★★★☆:高頻度で利用され、多くの一般的なカスタマイズで役立つ重要なパラメータ
★★★☆☆:中程度の頻度で利用され、特定の機能を実現する際に便利なパラメータ
★★☆☆☆:利用頻度はやや低めですが、特定の要件や細かな制御を行いたい場合に役立つパラメータ
★☆☆☆☆:利用頻度は低く、非常に限定的な状況や高度なカスタマイズでのみ使用されるパラメータ
関数名 | 主な役割・説明 (重要度/利用頻度) | 主要な引数 | 返り値 | 使用シーン / 注意点 |
---|---|---|---|---|
wp_create_nonce( $action = -1 ) |
★★★★★ 指定したアクション名に基づいてNonce(文字列トークン)を生成し、返します。 |
string|int $action (Nonceを紐付けるアクション名。ユニークな文字列推奨。省略時は-1) |
string (生成されたNonce) |
Ajaxリクエストに含めるNonceを生成する際や、カスタムURLにNonceを付加する際に使用。 |
wp_verify_nonce( $nonce, |
★★★★★ 渡されたNonceが、指定したアクション名に対して有効かどうかを検証します。 |
string $nonce (検証するNonce文字列),string|int $action (Nonce生成時に指定したアクション名) |
int|false (有効なら1または2(半分の有効期間内なら1、残り半分の有効期間なら2)、無効ならfalse) |
フォーム送信やURLパラメータで受け取ったNonceの正当性を確認する際に使用。返り値がfalse でないかで判定。 |
wp_nonce_field( $action = -1, |
★★★★★ Nonceを含む隠しフィールド ( ) をHTMLとして出力(または返す)。フォームのCSRF対策に必須です。 |
string|int $action (アクション名),string $name (Nonceフィールドのname属性値),boolean $referer (リファラーチェック用フィールドも出力するか),boolean $echo (trueで直接出力、falseで文字列として返す) |
string|void ($echo による) |
HTMLフォーム内に記述します。$name はデフォルトで_wpnonce 。 |
wp_nonce_url( $actionurl, |
★★★★☆ 指定したURLにNonceをクエリパラメータとして付加したURL文字列を返します。削除リンクなどGETリクエストで操作を行う場合に。 |
string $actionurl (ベースとなるURL),string|int $action (アクション名),string $name (Nonceのクエリパラメータ名) |
string (Nonceが付加されたURL) |
例: 削除 |
check_admin_referer( $action = -1, |
★★★★★ 管理画面や、同様の権限チェックが必要な処理の冒頭でNonceを検証します。検証に失敗すると、デフォルトでエラーメッセージを表示して処理を中断 ( wp_die() ) します。 |
string|int $action (アクション名),string $query_arg (Nonceのキー名、$_REQUEST から探す) |
false|void (検証失敗で処理中断。成功時は何も返さないことが多いが、状況によりint 1または2を返すこともある) |
管理画面でのフォーム処理、URLからのアクション実行処理の最初に呼び出す。 |
check_ajax_referer( $action = -1, |
★★★★★ AjaxリクエストのNonceを検証します。検証に失敗すると、デフォルトで -1 を出力して処理を中断します。 |
string|int $action (アクション名),string|false $query_arg (Nonceのキー名、$_REQUEST から探す。false の場合は_ajax_nonce または_wpnonce ),boolean $die (失敗時に処理を中断するか) |
int|false (検証成功なら1または2、失敗かつ$die=false ならfalse ) |
WordPressのAjaxハンドラ関数の冒頭で呼び出す。 |
wp_referer_field( $echo = true ) |
★★★☆☆ リファラー情報を検証するための隠しフィールド ( _wp_http_referer ) をHTMLとして出力(または返す)。wp_nonce_field() の第3引数$referer がtrue の場合に自動で含まれます。 |
boolean $echo |
string|void |
通常はwp_nonce_field() とセットで使われます。 |
Nonceのライフタイム(有効期間)
WordPressのNonceは、セキュリティを高めるために有効期限が設けられています。デフォルトでは、Nonceの有効期間は24時間です。これはWordPress内部で「tick」と呼ばれる時間単位(12時間)を2つ分として計算されます。wp_verify_nonce()
は、Nonceが最初の12時間以内に生成されたものであれば1
を、次の12時間以内に生成されたものであれば2
を返します。それ以降は無効(false
)となります。
この有効期間は、nonce_life
フィルターフックを使って変更することも可能ですが、セキュリティ上の理由から、通常はデフォルトのままか、より短い期間に設定することが推奨されます。
サンプルコード集 (Nonce活用の具体例)
1. フォーム処理でのNonce利用 (投稿削除の例)
フォーム内にNonceフィールドを設置し、送信先で検証します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
<?php // --- フォームを表示する側 (例: single.php など) --- // 特定の投稿を削除するためのフォーム(実際にはもっと確認処理が必要) if ( current_user_can( 'delete_post', $post_id_to_delete ) ) { echo '<form method="post" action="">'; // アクション名 'delete_post_' . $post_id_to_delete でNonceを生成・埋め込み wp_nonce_field( 'delete_post_' . $post_id_to_delete, 'my_delete_nonce' ); echo '<input type="hidden" name="post_id_to_delete" value="' . esc_attr( $post_id_to_delete ) . '">'; echo '<input type="hidden" name="action" value="my_delete_post_action">'; // 独自のaction名 echo '<button type="submit">この投稿を削除する</button>'; echo '</form>'; } // --- フォーム送信を処理する側 (例: functions.php や admin_post フックなど) --- // add_action( 'admin_post_my_delete_post_action', 'handle_my_delete_post' ); // admin_post フックの例 // add_action( 'init', 'handle_my_delete_post_on_init' ); // init フックの例 (より汎用的) function handle_my_delete_post_on_init() { if ( isset( $_POST['action'] ) && $_POST['action'] === 'my_delete_post_action' ) { if ( isset( $_POST['my_delete_nonce'] ) && isset( $_POST['post_id_to_delete'] ) ) { $post_id = absint( $_POST['post_id_to_delete'] ); // Nonceを検証 (アクション名はフォーム生成時と同じもの) if ( wp_verify_nonce( $_POST['my_delete_nonce'], 'delete_post_' . $post_id ) ) { // 権限チェック if ( current_user_can( 'delete_post', $post_id ) ) { wp_delete_post( $post_id ); // 投稿を削除 // wp_redirect( home_url('/?deleted=true') ); // 削除後のリダイレクト // exit; echo "投稿ID: " . $post_id . " を削除しました。(実際の処理)"; } else { wp_die('権限がありません。'); } } else { wp_die('セキュリティトークンが無効です。'); } } } } ?> |
管理画面内の処理であれば、check_admin_referer()
を使うとより簡潔に検証とエラー処理が行えます。
2. URLを使ったアクションでのNonce利用 (設定変更リンクの例)
「設定を有効化」のようなリンクにNonceを付加し、リンク先で検証します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
<?php // --- リンクを生成する側 --- $item_id = 123; // 例 $action_name = 'activate_setting_' . $item_id; $base_url = admin_url('admin.php?page=my-settings&action=activate&item_id=' . $item_id); $nonce_url = wp_nonce_url( $base_url, $action_name, 'my_activation_nonce' ); echo '<a href="' . esc_url( $nonce_url ) . '">設定ID:' . $item_id . 'を有効化</a>'; // --- リンク先で処理する側 (例: admin_init や admin_menu で登録したページのコールバック関数内) --- if ( isset( $_GET['action'] ) && $_GET['action'] === 'activate' && isset( $_GET['item_id'] ) ) { $item_id = absint( $_GET['item_id'] ); // Nonceを検証 (アクション名、Nonceキー名はリンク生成時と同じもの) // check_admin_referer() は $_REQUEST['my_activation_nonce'] を自動で探す if ( check_admin_referer( 'activate_setting_' . $item_id, 'my_activation_nonce' ) ) { // 権限チェック (例) if ( current_user_can( 'manage_options' ) ) { // 設定を有効化する処理 // update_option( 'setting_item_' . $item_id . '_active', true ); echo "設定ID: " . $item_id . " を有効化しました。(実際の処理)"; } else { wp_die('権限がありません。'); } } else { // check_admin_referer は失敗時に自動で wp_die() するので、ここは通常通らない // (第2引数に false を渡した場合を除く) wp_die('セキュリティチェックに失敗しました。'); } } ?> |
3. Ajax処理でのNonce利用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
<?php // --- PHP側: NonceをJavaScriptに渡す (例: functions.php) --- function my_enqueue_ajax_scripts() { wp_enqueue_script( 'my-ajax-script', get_template_directory_uri() . '/js/my-ajax.js', array('jquery'), null, true ); // Nonceを生成してJavaScriptオブジェクトに渡す wp_localize_script( 'my-ajax-script', 'my_ajax_obj', array( 'ajax_url' => admin_url( 'admin-ajax.php' ), 'nonce' => wp_create_nonce( 'my_ajax_action_nonce' ) // Ajaxアクション用のNonce )); } add_action( 'wp_enqueue_scripts', 'my_enqueue_ajax_scripts' ); // フロントエンドの場合 // add_action( 'admin_enqueue_scripts', 'my_enqueue_ajax_scripts' ); // 管理画面の場合 // --- PHP側: Ajaxハンドラ関数 (例: functions.php) --- function my_ajax_handler() { // Nonceを検証 (アクション名、キー名は wp_localize_script で渡したキー、またはデフォルトで 'security' や '_ajax_nonce') // check_ajax_referer() の第2引数でキー名を指定できる。省略すると 'security' を探す。 // 今回は wp_localize_script で 'nonce' というキーで渡したので、Ajax側で 'security' という名前で送るか、 // check_ajax_referer の第2引数に 'nonce' を指定する。 // ここではAjaxリクエスト時に 'security' というパラメータ名でnonce値を送る想定。 check_ajax_referer( 'my_ajax_action_nonce', 'security' ); // Ajax処理... $response_data = array( 'message' => 'Ajax処理成功!データ: ' . sanitize_text_field($_POST['some_data']) ); wp_send_json_success( $response_data ); // 成功レスポンスをJSONで返す // wp_send_json_error( array('message' => 'エラーが発生しました。') ); // エラーの場合 // wp_die(); // check_ajax_referer で $die=true (デフォルト) なら不要なことが多い } // wp_ajax_{action} はログインユーザー用、wp_ajax_nopriv_{action} は非ログインユーザー用 add_action( 'wp_ajax_my_custom_ajax_action', 'my_ajax_handler' ); // add_action( 'wp_ajax_nopriv_my_custom_ajax_action', 'my_ajax_handler' ); /* --- JavaScript側 (my-ajax.js) --- jQuery(document).ready(function($) { $('#my-ajax-button').on('click', function() { $.ajax({ url: my_ajax_obj.ajax_url, // admin-ajax.php type: 'POST', data: { action: 'my_custom_ajax_action', // PHP側のフック名に合わせる security: my_ajax_obj.nonce, // Nonce値を 'security' というキーで送信 some_data: 'これはテストデータです' }, success: function(response) { if(response.success) { console.log('サーバーからのメッセージ:', response.data.message); } else { console.error('エラー:', response.data.message); } }, error: function(errorThrown) { console.error('AJAXエラー:', errorThrown); } }); }); }); */ ?> |
Nonce利用時の注意点とベストプラクティス
- アクション名の一致: Nonceを生成する際 (
wp_create_nonce
,wp_nonce_field
,wp_nonce_url
) と検証する際 (wp_verify_nonce
,check_admin_referer
,check_ajax_referer
) で、アクション名($action
引数)を完全に一致させることが最も重要です。これが異なると検証に失敗します。 - 適切なタイミングでの検証: データ変更、削除、設定更新など、状態を変更する可能性のあるリクエストを受け取ったら、実際の処理を行う直前に必ずNonceを検証してください。
- Nonceの使い回しを避ける: 特定のアクションやリソースに対してユニークなアクション名でNonceを生成・検証するように心がけ、Nonceを複数の異なる操作で使い回すのは避けましょう。
- HTTPSの推奨: NonceはCSRF対策には有効ですが、中間者攻撃(MITM)によってNonce自体が盗聴されるリスクは残ります。サイト全体をHTTPSで運用することが、Nonceを含む通信の安全性を高める上で不可欠です。
- キャッシュとの相性: Nonceは時間やユーザーセッションに依存するため、ページ全体がキャッシュされるような環境では問題が生じることがあります。キャッシュされたページに埋め込まれた古いNonceでは検証に失敗するためです。このような場合は、NonceをAjaxで動的に取得・埋め込むなどの工夫が必要になることがあります。
- 権限チェックも忘れずに: Nonceはリクエストの意図を確認しますが、その操作を実行する権限がユーザーにあるかどうかは別途
current_user_can()
などでチェックする必要があります。
よくある質問 (FAQ)
- Q1: Nonceを使えば、クロスサイトスクリプティング (XSS) 攻撃も防げますか?
- A1: いいえ、Nonceの主な目的はCSRF(クロスサイトリクエストフォージェリ)攻撃を防ぐことです。XSS攻撃を防ぐためには、入力値のサニタイズと出力値の適切なエスケープ処理が別途必要です。Nonceは、リクエストが正当なユーザーインターフェースから来たものであることを確認する役割が中心です。
- Q2: Nonceの有効期限は変更できますか?
- A2: はい、
nonce_life
というフィルターフックを使うことで、Nonceの有効期間(デフォルトは約24時間)を秒単位で変更できます。ただし、セキュリティ上の理由から、有効期間を不必要に長くすることは推奨されません。 - Q3: ログアウトしているユーザー(非ログインユーザー)に対してNonceは機能しますか?
- A3: はい、機能します。非ログインユーザーの場合、NonceはユーザーIDの代わりにセッション情報(IPアドレスなども考慮されることがあります)に基づいて生成・検証されることがあります。ただし、その有効性やセキュリティレベルはログインユーザーの場合とは異なる側面があるため、どのような操作を非ログインユーザーに許可するかは慎重に検討する必要があります。例えば、公開フォームからのスパム対策としての限定的な利用などが考えられます。
まとめ
WordPressにおけるNonceは、サイトとユーザーをCSRF攻撃から守るための非常に重要なセキュリティ機能です。フォーム処理、URLを通じたアクション、Ajaxリクエストなど、状態を変更する可能性のあるあらゆるリクエストに対して、Nonceの生成と検証を正しく実装することが、安全なWordPressサイトを開発・運用する上での基本となります。このチートシートを参考に、Nonceの適切な使い方をマスターし、サイトのセキュリティを一層強化してください。
私たちは、埼玉県川越市に根差しながら、WordPressサイトのセキュリティ診断、脆弱性対応、そしてセキュアなカスタマイズやプラグイン開発に関する専門的なコンサルティングと実装サービスを提供しています。オンラインを通じて全国のクライアント様からのご相談に対応可能ですので、セキュリティに関するお悩みがあれば、ぜひ一度お声がけください。
WordPress顧問エンジニアサービスをご検討くださいね。お客様のサイトのセキュリティ強化や、開発チームのセキュリティ意識向上をサポートします。