WordPress での CSRF 対策

nonce ってナンスか?

春だというのに寒いですねぇw

それはさておき、みなさんは nonce という言葉を聞いたことがあるでしょうか? 日本ではあまり馴染みがないように思いますが、コンピュータ (というか暗号) の世界では一度だけ使われる使い捨てのユニークな数 (英語版 Wikipedia の説明) のことを言います。

WordPress には CSRF 対策として nonce という機能が実装されています。 wp_create_nonce で nonce を生成し、wp_verify_nonce でこれを検証することができます。 リンク先の Codex にも例がありますが、wp_create_nonce で生成した nonce を HTML のフォームに埋め込み、サーバーで受けたその値を wp_verify_nonce で検証する、というような使い方ができます。

ただし、注意点が一つあります。 WordPress の nonce は本来の意味の nonce とは異なり、ワンタイムの使い捨てというわけではありません。 12時間ごとに変更され、検証に際しては 24時間有効です。 もっとも CSRF 対策として考えたとき、ワンタイムである必要はありません (例えば高木先生の記事)。 推測されないようにきちんとランダムであれば、そして有効期間が適切であれば CSRF 対策として十分です。

wp_verify_nonce は、現在の nonce の値と同じならば 1、1つ前の nonce と同じならば 2を返します。 つまりデフォルトでは 0-12時間で 1、12-24時間で 2が返されることになります (時間の数え方は後述)。 nonce が一致しなければ wp_verify_nonce は 0を返すので、通常はこれをそのまま真偽判定条件式として使用します。

有効期間の短縮

その有効期間ですが、デフォルトの 24時間を短縮したいときは add_filter することで変えられます。

add_filter( 'nonce_life', 'my_nonce_life' );

function my_nonce_life() {
    return 3600; /* 1 hour */
}

このテクニックはテスト時にも使えそうですね。

なお、この有効期間は wp_create_nonce を呼んだ時からカウントダウンが始まるわけではなく、time() の値を使って周期的に変えているだけなので、ちょうど変わり目 (GMT の 0時とか 12時とか) にあたると短時間で値が変化することになります。 それでも先述の通り一つ前の nonce まで有効と判定されるので通常は問題ないでしょう。

nonce の素

さて、この nonce ですが、以下の情報を元に生成されます。

  1. ユーザー ID
  2. 時刻 (といっても 12時間単位)
  3. wp_create_nonce に渡された引数 $action
  4. サイト毎に持っている秘密キーと Salt

これらが同一であれば同じ値になります。 ここで開発者にとって気になるのは 4. の秘密キーと Salt ではないでしょうか? そして自分の wp-config.php に以下のような記述を見つけて焦るわけです。

define('AUTH_KEY',         'put your unique phrase here');
define('SECURE_AUTH_KEY',  'put your unique phrase here');
define('LOGGED_IN_KEY',    'put your unique phrase here');
define('NONCE_KEY',        'put your unique phrase here');
define('AUTH_SALT',        'put your unique phrase here');
define('SECURE_AUTH_SALT', 'put your unique phrase here');
define('LOGGED_IN_SALT',   'put your unique phrase here');
define('NONCE_SALT',       'put your unique phrase here');

これを見ると「げっ、ウチのサイト、ヤバい??!」と思ってしまいますよね。

でも、安心してください。 実はこのような wp-config.php となっている場合は、自動的に秘密キーと Salt を生成してデータベースに保存し、それを使ってくれます。 このままでも「put your unique phrase here」をキーとして使うことにはなりません。

となると wp-config.php を書き換えたくなるのは定期的にキーを変更したい場合ぐらいでしょうか。 生成には https://api.wordpress.org/secret-key/1.1/salt/ を使いましょう。

学習のために

興味のある人は wp-include/pluggable.php の nonce 関連関数を読んでみましょう。

私が WordPress の nonce について知ったのは「Professional WordPress Plugin Development」という書籍によってです。 この書籍は WordPress のプラグイン開発に必要な情報が一通りまとまっており、分量も重くないのでお勧めです。 英語も難しくないですし。

英語ついでですが、こちらの WordPress の nonce についての記事も参考情報として挙げておきます。


2013.4.17 追記

nonce の変わり目の際の動作について訂正。(一つ前の値も有効なので変化してもすぐに verify エラーになるわけではない)