なぜノンスを使用するのか?
ノンスが使用される理由の例として、管理者画面が投稿番号123を削除するURLを生成することを考えてみてください。
そのURLにアクセスすると、WordPressは認証クッキー情報を検証し、その投稿を削除する権限がある場合は削除を進めます。攻撃者がこれを利用できるのは、あなたの知らないうちにそのURLにブラウザをアクセスさせることです。たとえば、攻撃者は次のような3者ページに偽装リンクを作成することができます:
`````<img src="http://example.com/wp-admin/post.php?post=123&action=trash" />
これにより、ブラウザはWordPressにリクエストを送信し、ブラウザは自動的に認証クッキーを添付し、WordPressはこれを有効なリクエストと見なします。
ノンスを追加することで、これを防ぐことができます。たとえば、ノンスを使用する場合、WordPressがユーザーのために生成するURLは次のようになります:
誰かがWordPressによって生成され、ユーザーに与えられた正しいノンスなしに投稿番号123を削除しようとすると、WordPressはブラウザに「403 Forbidden」レスポンスを送信します。
<a name="creating-a-nonce"></a>
## ノンスの作成
ノンスを作成し、URLのクエリ文字列に追加することができます。また、フォームの隠しフィールドに追加することも、他の方法で使用することもできます。
AJAXリクエストで使用されるノンスの場合、ノンスを隠しフィールドに追加し、JavaScriptコードがそれを取得できるようにするのが一般的です。
ノンスは現在のユーザーのセッションに固有であるため、ユーザーが非同期にログインまたはログアウトすると、ページ上のノンスはもはや有効ではなくなります。
<a name="customize-nonces-for-guests-non-logged-in-users"></a>
### ゲスト(ログインしていないユーザー)のためのノンスのカスタマイズ
WordPressコアは、デフォルトでゲストに対して同じノンスを生成します。なぜなら、彼らは同じユーザーID(値`````0`````)を持っているからです。つまり、ゲストがCSRF攻撃を受けるのを防ぐことはありません。このセキュリティ面を強化するために、ゲスト用のセッションメカニズムを開発し、[nonce_user_logged_out](https://developer.wordpress.org/reference/hooks/nonce_user_logged_out/)フィルターにフックして、ユーザーIDの値`````0`````をセッションメカニズムからの別のランダムIDに置き換えることができます。
<a name="adding-a-nonce-to-a-url"></a>
### URLにノンスを追加する
URLにノンスを追加するには、`````wp_nonce_url()`````を呼び出し、ベアURLとアクションを表す文字列を指定します。たとえば:
``````bash
$complete_url = wp_nonce_url( $bare_url, 'trash-post_'.$post->ID );
`
最大限の保護を確保するために、アクションを表す文字列ができるだけ具体的であることを確認してください。
デフォルトでは、wp_nonce_url()
は_wpnonce
という名前のフィールドを追加します。関数呼び出しで異なる名前を指定できます。たとえば:
$complete_url = wp_nonce_url( $bare_url, 'trash-post_'.$post->ID, 'my_nonce' );
フォームにノンスを追加する
フォームにノンスを追加するには、wp_nonce_field()
を呼び出し、アクションを表す文字列を指定します。デフォルトでは、wp_nonce_field()
は2つの隠しフィールドを生成します。1つはノンスの値、もう1つは現在のURL(リファラー)の値であり、結果をエコーします。たとえば、この呼び出し:
wp_nonce_field( 'delete-comment_'.$comment_id );
は次のようなものをエコーするかもしれません:
<input type="hidden" id="_wpnonce" name="_wpnonce" value="796c7766b1" />
<input type="hidden" name="_wp_http_referer" value="/wp-admin/edit-comments.php" />
最大限の保護を確保するために、アクションを表す文字列ができるだけ具体的であることを確認してください。
ノンスフィールドの異なる名前を指定したり、リファラーフィールドを不要と指定したり、結果をエコーせずに返すように指定したりできます。構文の詳細については、wp_nonce_field()
を参照してください。
他の方法で使用するためのノンスの作成
他の方法で使用するためのノンスを作成するには、wp_create_nonce()
を呼び出し、アクションを表す文字列を指定します。たとえば:
$nonce = wp_create_nonce( 'my-action_'.$post->ID );
これにより、ノンス自体が返されます。たとえば:295a686963
最大限の保護を確保するために、アクションを表す文字列ができるだけ具体的であることを確認してください。
ノンスの検証
URL、管理画面のフォーム、AJAXリクエスト、または他のコンテキストで渡されたノンスを検証できます。
管理画面から渡されたノンスの検証
URLまたは管理画面のフォームで渡されたノンスを検証するには、check_admin_referer()
を呼び出し、アクションを表す文字列を指定します。
たとえば:
check_admin_referer( 'delete-comment_'.$comment_id );
この呼び出しはノンスとリファラーをチェックし、チェックが失敗した場合は通常のアクションを実行します(「403 Forbidden」レスポンスとエラーメッセージでスクリプトの実行を終了します)。
ノンスを作成するときにデフォルトのフィールド名(_wpnonce
)を使用しなかった場合は、フィールド名を指定してください。
たとえば:
check_admin_referer( 'delete-comment_'.$comment_id, 'my_nonce' );
AJAXリクエストで渡されたノンスの検証
AJAXリクエストで渡されたノンスを検証するには、check_ajax_referer()を呼び出し、アクションを表す文字列を指定します。たとえば:
check_ajax_referer( 'process-comment' );
この呼び出しはノンスをチェックします(ただしリファラーはチェックしません)し、チェックが失敗した場合はデフォルトでスクリプトの実行を終了します。
ノンスを作成するときにデフォルトのフィールド名(_wpnonce
または_ajax_nonce
)のいずれかを使用しなかった場合、または実行を終了するのではなく他のアクションを実行したい場合は、追加のパラメータを指定できます。詳細については、check_ajax_referer()
を参照してください。
他のコンテキストで渡されたノンスの検証
他のコンテキストで渡されたノンスを検証するには、wp_verify_nonce()
を呼び出し、ノンスとアクションを表す文字列を指定します。
たとえば:
wp_verify_nonce( $_REQUEST['my_nonce'], 'process-comment'.$comment_id );
結果がfalseの場合、リクエストの処理を続行しないでください。代わりに、適切なアクションを取ってください。通常のアクションは、wp_nonce_ays()
を呼び出し、ブラウザに「403 Forbidden」レスポンスを送信します。
ノンスシステムの変更
さまざまなアクションやフィルターを追加することで、ノンスシステムを変更できます。
ノンスの有効期限の変更
デフォルトでは、ノンスの有効期限は1日です。その後、アクション文字列と一致していても、ノンスは無効になります。有効期限を変更するには、ノンスの有効期限を秒単位で指定するnonce_lifeフィルターを追加します。
たとえば、有効期限を4時間に変更するには:
add_filter( 'nonce_life', function () { return 4 * HOUR_IN_SECONDS; } );
追加の検証の実行
ノンスとリファラーが有効であることがcheck_admin_referrer()
によって確認されたときに、追加の検証を実行するには、check_admin_referer
アクションを追加します。
たとえば:
function wporg_additional_check ( $action, $result ) {
...
}
add_action( 'check_admin_referer', 'wporg_additional_check', 10, 2 );
<a name="changing-the-error-message"></a>
### エラーメッセージの変更
ノンスが無効な場合に送信されるエラーメッセージを、翻訳システムを使用して変更できます。たとえば:
``````bash
function my_nonce_message ($translation) {
if ($translation === 'Are you sure you want to do this?') {
return 'No! No! No!';
}
return $translation;
}
add_filter('gettext', 'my_nonce_message');
`
追加情報
このセクションには、WordPressのノンスシステムに関する追加情報が含まれており、時折役立つかもしれません。
ノンスの有効期限
WordPressのノンスが「一度だけ使用される番号」ではないのと同様に、ノンスの有効期限も本当にノンスの有効期限ではありません。WordPressは2つのティック(有効期限の半分)を持つシステムを使用し、現在のティックと最後のティックからノンスを検証します。デフォルト設定(24時間の有効期限)では、これはUnixエポックから経過した12時間の期間に関連しています。つまり、正午と真夜中の間に作成されたノンスは、翌日の正午まで有効です。したがって、実際の有効期限は12時間から24時間の間で変動します。
ノンスが有効な場合、ノンスを検証する関数は現在のティック番号、1または2を返します。この情報を使用して、たとえば、2回目のティックにあるノンスを更新し、期限切れにならないようにすることができます。
ノンスのセキュリティ
ノンスは、WordPressを正しくインストールした場合、サイトに固有のキーとソルトを使用して生成されます。NONCE_KEY
とNONCE_SALT
はwp-config.php
ファイルで定義されており、そのファイルには詳細情報を提供するコメントが含まれています。
ノンスは認証や承認、アクセス制御に依存してはなりません。current_user_can()
を使用して関数を保護し、常にノンスが侵害される可能性があると仮定してください。
ノンスシステムの置き換え
ノンスシステムを構成するいくつかの関数はプラグ可能であり、独自の関数を提供することで置き換えることができます。
管理リクエストやAJAXリクエストの検証方法を変更するには、check_admin_referrer()
またはcheck_ajax_referrer()
、またはその両方を置き換えることができます。
他のノンスシステムでノンスシステムを置き換えるには、wp_create_nonce()
、wp_verify_nonce()
、およびwp_nonce_tick()
を置き換えることができます。
関連情報
ノンス関数:wp_nonce_ays()
、wp_nonce_field()
、wp_nonce_url()
、wp_verify_nonce()
、wp_create_nonce()
、check_admin_referer()
、check_ajax_referer()
、wp_referer_field()
ノンスフック:nonce_life
、nonce_user_logged_out
、explain_nonce_(verb)-(noun)
、check_admin_referer