こんにちは。でんすけ(@notgeek_densuke)です。
前回、WordPress上でAjaxを使って、
サーバー側とクライアント側でデータをやり取りする方法を書きました。
今回は、よりセキュアなやり方を書きます。
スポンサーリンク
セキュアなAjaxの必要性
前回の記事のように、データをやり取りして、それをそのままサイトの表示に反映させるだけ、であれば、HTMLのエスケープを考慮するぐらいで大きな問題はなさそうなのですが。
気を付けたいのは、データベースへ読み書きする場合、
悪意のある操作をされるとDB上のデータを読み取られたり、サイトそのものを書き換えられる危険性があります。
ということで、DBを扱う際に推奨されている実装方法として、
nonce(ナンス)を使った実装方法を書いてみます。
nonce(ナンス)とは
nonce(ナンス)とは、
使い捨てのために一時的に生成される値のこと。
ちょっとニュアンスは違いますが、ワンタイムパスワード、みたいなものです。
最近では、ビットコインのマイニングやブロックチェーンの技術に関して出てくる言葉だったりしますが、
セキュリティ関連のさまざまな場面でnonce値という概念が使われます。
WordPressでも、このnonce値を生成する機能を持っています。
nonce値自体は予測のできないランダムな値で、それを送受信時のデータに使うことで、
CSRF攻撃(クロスサイトリクエストフォージェリ)対策になります。
特に、DBを扱うスクリプトを書く際は、セキュリティの観点上、
このnonce値をチェックする方法で実装することが推奨されています。
では、具体的にどうやって使うかを解説していきます。
nonce値を使ったセキュア実装の流れ
おおまかにどういう流れになるかというと。
・PHP側でnonce値の生成
・JS側で値を使えるように引き渡し
・JS側でAjax通信、nonce値も送信データに含めてPHP側へ送る
・PHP側で受信して、nonce値をチェック、DB読み書きなどの処理
という流れです。
nonce値を生成してJSに渡す
まずは、nonce値を生成して、JS側で使えるようにします。
PHP側の実装はこんな感じ。
function my_enqueue_scripts() { // JSファイルにhandle名を付ける $handle = 'myscript'; // Ajaxのアクション名 $action = 'ajaxtest'; // jsファイルの読み込み(includeディレクトリ配下に自作JSファイルを置く想定) wp_enqueue_script($handle, includes_url() . 'js/ajaxtest/ajaxtest.js', array( 'jquery') ); // JS側へ、Ajaxで使う各種パラメータを渡す wp_localize_script( $handle, 'MyAjax', array( 'url' => admin_url( 'admin-ajax.php' ), 'action' => $action, 'nonce' => wp_create_nonce( $action ), ) ); } add_action( 'wp_enqueue_scripts', 'my_enqueue_scripts' );
「wp_enqueue_script」で、JSファイルを読み込みます。
具体的には、HTMLページにこんなタグが出力されるイメージです。
<script type="text/javascript" src="https://ブログのドメイン/wp-includes/js/ajaxtest/ajaxtest.js"></script>
読み込んだスクリプトには、任意でハンドルネームを付けることができます。
任意でいいですが、「jquery」のようにデフォルトで既に登録されているハンドルネームもあるので、
被らないような無難な名前にしておきましょう。
また、第3引数には依存するライブラリのハンドルネームを、配列で指定することができます。
「ajaxtest.js」の中でjQueryを使うことを想定して、array(‘jquery’)を指定しています。
で、「wp_localize_script」で、Ajaxに関する値をJS側で使えるようにします。
指定したハンドルネームのスクリプトがページに読み込まれている場合のみ、実行されます。
具体的には、HTMLページにこんなタグが出力されるイメージ。
<script type="text/javascript"> /* <![CDATA[ */ var MyAjax = { "url":"https:\/\/ブログドメイン\/wp-admin\/admin-ajax.php", "action":"ajaxtest", "nonce":"生成されたナンス値" }; /* ]]> */ </script>
PHP側で「wp_create_nonce」でナンス値を生成し、JS側に渡しています。
「wp_create_nonce」は、アクション名をキーにして、その他に日時などのデータをもとにして、
なんだかごちゃごちゃ計算をして、予測こんなな英数字の文字列に変換してくれます。
JavaScript側からnonce値を使ってAjax通信
では、今度はJS側の実装。
先ほど「wp_enqueue_script」で読み込んだ「ajaxtest.js」の中身です。
実装例として、フォームのsubmitでPOSTデータを送ることを想定したソース例です。
jQuery(function($){ $( '#ajaxtestforms' ).submit( function(event){ event.preventDefault(); var fd = new FormData( this ); // Ajaxのアクションを指定 fd.append('action' , MyAjax.action ); // nonce値を指定 fd.append('nonce' , MyAjax.nonce ); // Ajaxでデータ送信 $.ajax({ type: 'POST', url: MyAjax.url, data: fd, processData: false, contentType: false, success: function( response ){ //通信成功時の処理 } }); return false; }); });
はい。
さきほどPHP側から「wp_localize_script」で引き渡した値が、
MyAjax.action、MyAjax.nonceなどの形で使われています。
fd.append(‘nonce’ , MyAjax.nonce );
のような形で、nonce値をAjaxの送信データに含めて送ることで、PHP側でチェックすることができるようになります。
PHP側でnonce値のチェック
送信されてきたAjaxデータに対して、PHP側で受けたときの処理です。
こんな感じ。
function ajaxTestFunc(){ // nonce値のチェック if ( isset( $_REQUEST['nonce'] ) && wp_verify_nonce( $_REQUEST['nonce'], 'ajaxtest' ) ) { /* ここにAjax受信時の処理を書く */ // こっちの関数は、nonce値チェックエラーならすぐにdie()する check_ajax_referer( 'ajaxtest', 'nonce'); } } add_action( 'wp_ajax_ajaxtest' , 'ajaxTestFunc' ); add_action( 'wp_ajax_nopriv_ajaxtest' , 'ajaxTestFunc' );
「wp_verify_nonce」でnonce値が合わない場合はfalseを返します。
あるいは、「check_ajax_referer」で、合わない場合はその場でdie()します。
あとは、Ajax受信時の処理を好きなように書くだけです。
ちなみに、WordPressでPHP側からDBを扱う実装に関しては、こちらの記事も参考にどうぞ。
WordPress、nonce値の有効期限
ちなみに、WordPressのデフォルト設定では、nonce値の有効期限は約24時間です。
nonce値生成後24時間というわけではなく、24時間サイクルでnonce値が変わる、という感じ。
もうちょっと正確にいうと、
12時間サイクルでnonce値は変わるんだけど、1サイクル前のnonce値もチェックOKにしてあげている、という感じです。
24時間だったら長くて心配!という場合は、有効期限を変更することも可能です。
functions.phpなどにこんな感じで実装できます。
function my_nonce_life() { return 3600; /* 有効期限1時間 = 3600秒 */ } add_filter( 'nonce_life', 'my_nonce_life' );
ただし、WordPressでは色んな所でこのnonce値が使われており、
例えばログインの有効性をチェックするのにnonce値が使われていたりするので注意です。
例えば記事投稿画面。
1時間以上かけて記事を書いていたらnonce値が変わったので、下書き保存が無効と判断されて泣きそうになる・・・
なんてことになったりします。
有効期限を変更する場合は注意してください。
まとめ
ということで、nonceを使ってセキュアなAjaxを使おう、という話でした。
nonce値の生成、送信処理それぞれの実装自体はそれほど難しくないので
DBを扱う処理を書く場合は、セキュリティ観点からnonceの実装をするようにしましょう。
それではまたー。
コメント
コメントはありません。