そんなにGeekじゃないエンジニアブログ

[WordPress]Ajaxをよりセキュアに使ってDBへのアクセスなどを実行する

calendar

こんにちは。でんすけ(@notgeek_densuke)です。

前回、WordPress上でAjaxを使って、
サーバー側とクライアント側でデータをやり取りする方法を書きました。

[WordPress]Ajaxを使ってデータをPOST!非同期にデータをやり取りする方法

今回は、よりセキュアなやり方を書きます。

スポンサーリンク

セキュアな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ブログでDBの独自テーブルを作ってwpdbで操作する方法

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の実装をするようにしましょう。

それではまたー。

この記事をシェアする

コメント

コメントはありません。

down コメントを残す




CAPTCHA


このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください