WordPressの開発において、セキュリティ対策は不可欠です。
特にCSRF(クロスサイトリクエストフォージェリ)攻撃への対策として、WordPressではnonce(ナンス)と呼ばれるトークンを使用します。
本記事では、CVE-2025-1463(Spreadsheet IntegrationプラグインのCSRF脆弱性)を例に、WordPressテーマやプラグインの開発者が安全な機能開発にステップアップできるように、nonceの使い方を詳しく解説します。
目次
CVE-2025-1463とは?
CVE-2025-1463は、WordPressのSpreadsheet Integrationプラグインに発生したCSRFの脆弱性です。
https://nvd.nist.gov/vuln/detail/CVE-2025-1463
問題の原因
- WordPressにはnonceを使ったCSRF対策の仕組みがあるが、このプラグインではnonceチェックが適切に実装されていなかった。
- その結果、攻撃者が管理者に悪意のあるリクエストを送信させることが可能になった。
- 具体的には、管理者が特定のリンクをクリックするだけで、意図しない投稿の公開や設定変更が行われる可能性があった。
このような問題を防ぐために、nonceの正しい実装が重要になります。
(ちなみに、該当の脆弱性は既に解決済みでプラグインのアップデートをすることで堅牢な処理になります。)
修正コードはこちらで確認できます: https://plugins.trac.wordpress.org/changeset/3250077/#file352
CSRFによる問題点
CSRF(クロスサイトリクエストフォージェリ)は、攻撃者がユーザーのブラウザを悪用し、意図しないリクエストを送信させる攻撃です。
CSRFの危険性
- 管理者権限の乗っ取り:
管理者がログイン中の状態で悪意のあるリンクを踏むと、意図しない投稿の公開・削除、設定の変更が行われる可能性があります。 - データ改ざん:
ユーザーのアカウント情報を変更するリクエストを送信されると、被害者は知らない間にパスワードを変更されることがあります。 - 不正送金やアカウントの悪用:
ECサイトや銀行系のシステムでは、CSRFにより不正な取引が発生することもあります。
CSRFの具体的な攻撃手法
攻撃者が悪意のあるWebページを作成
攻撃者は、対象サイトの特定の機能(投稿の削除、設定変更など)を実行するための悪意のあるリクエストを含んだページを作成します。
権限を持つユーザーを誘導
攻撃者は、ターゲットユーザー(例:WordPressの管理者)をそのページに誘導するため、
- フィッシングメール
- SNSのメッセージ
- 広告
などを使用してクリックさせます。
ユーザーがリンクをクリックすると不正リクエストが送信される
被害者がログイン中の状態でそのページを開くと、意図しないリクエストが発生し、サイトの設定が変更される可能性があります。
本件のCSRFは過去のmixiで起きた事例が参考になります。
これを防ぐために、nonceの正しい実装が必要になります。
WordPressのnonceとは?
nonce(ナンス)は、一時的に有効なユニークなトークンで、CSRF攻撃を防ぐために使用されます。WordPressの標準機能として提供されており、以下の特徴があります。
- セッションごとに一意のトークンを発行
- 特定のアクション(delete_postなど)に対して有効
- 一定時間(デフォルト12時間)で無効になる
この仕組みにより、悪意のあるサイトからの不正なリクエストをブロックできます。
WordPressでのnonceの使い方
nonceの生成(フォームやリンクに埋め込む)
フォームのnonce埋め込み
<form method="post" action="admin-post.php">
<?php wp_nonce_field('delete_post', 'my_nonce'); ?>
<input type="hidden" name="post_id" value="123">
<input type="submit" value="削除">
</form>
wp_nonce_field($action, $name)
を使用すると、隠しフィールドにnonceが埋め込まれるため、安全なリクエストが可能になります。
$action
(delete_post) → このnonceが有効なアクション名$name
(my_nonce) → フォーム内のname
属性
リンクにnonceを付与(GETリクエスト用)
$url = add_query_arg('_wpnonce', wp_create_nonce('delete_post'), 'admin.php?page=delete&id=123');
echo '<a href="' . esc_url($url) . '">削除</a>';
wp_create_nonce('delete_post')
で生成されたnonceをGETパラメータとして付与します。
nonceの検証(リクエストをチェック)
POSTリクエストのnonce検証
if ( ! isset($_POST['my_nonce']) || ! wp_verify_nonce($_POST['my_nonce'], 'delete_post') ) {
wp_die('Security check failed');
}
isset($_POST['my_nonce'])
→ nonceが送信されているか確認wp_verify_nonce($_POST['my_nonce'], 'delete_post')
→ nonceが正しいか検証
管理画面用のnonceチェック(フォーム送信時)
if (isset($_POST['submit'])) {
check_admin_referer('delete_post', 'my_nonce');
// 正常な処理を実行
}
check_admin_referer()
は、nonceのチェックを簡単に実装できるWordPress標準関数です。
Ajaxリクエストのnonceチェック
フロントエンドでnonceを送信
jQuery.post(
ajaxurl,
{
action: 'delete_post',
security: my_ajax_object.nonce,
post_id: 123
},
function(response) {
console.log(response);
}
);
サーバー側(functions.php)のnonceチェック
add_action( 'wp_ajax_delete_post', 'delete_post_function' );
function delete_post_function() {
check_ajax_referer('delete_post', 'security');
$post_id = intval($_POST['post_id']);
wp_delete_post($post_id);
wp_send_json_success('削除しました');
}
check_ajax_referer('delete_post', 'security');
でnonceを検証- CSRF攻撃を防ぐための標準的な方法
まとめ
関数 | 説明 |
---|---|
wp_create_nonce($action) | nonceを生成 |
wp_verify_nonce($nonce, $action) | nonceを検証 |
wp_nonce_field($action, $name) | フォームにnonceを埋め込む |
check_admin_referer($action, $name) | 管理画面用のnonceチェック |
check_ajax_referer($action, $name) | Ajaxリクエストのnonceチェック |
開発者として次のステップへ
WordPressで機能を開発する際には、CSRF対策としてnonceを正しく実装することが必須です。
特に、
- 管理画面の操作
- 投稿の削除・編集機能
- Ajaxリクエスト
を開発する際は、適切にnonceを使用して安全なコードを書く習慣を身につけましょう。
今後のステップとして、
REST API
でのnonceの扱いwp_rest_nonce
を利用したAPI認証
など、さらに高度なセキュリティ対策も学んでいくことをおすすめします。
コメントを残す