SMART LLC

タイミング攻撃対策

公開日:2014/10/13

crypt()関数を使ってパスワードをハッシュする方法の続き。
タイミング攻撃なる脅威の対策について調べたのでメモする。

タイミング攻撃

「==」とか「===」のような比較演算子を使ってパスワードをチェックしている場合、パスワードの長さの正否や何文字目まで合っているかで処理時間が変わる。
これを利用して処理時間を計測してパスワードを特定するのがタイミング攻撃。
タイミング攻撃の対策方法はランダムな遅延を発生させる方法と比較演算子を使わないで内容に関わらず処理時間を一定にする方法がある。
PHPではバージョン5.5でpassword_verify()関数、5.6でhash_equals()関数が追加され、これを使うと処理時間を一定にしたチェックができる。
が、ドメインキングのバージョンは5.3.3_(:3 」∠)_
自力でタイミング攻撃対策をする必要がある。
ランダムな遅延を発生させる方法が楽そうだけどPHPのマニュアルでも情報セキュリティスペシャリストの過去問題でも処理時間を一定にしろて書いてる。
というわけで処理時間を一定にすることでタイミング攻撃を防ぐプログラムをつくってみる。

排他的論理和(XOR演算)で文字列比較

だいぶ調べたつもりだけどタイミング攻撃の対策をしたプログラムを具体的に書いてある記事があまり見つからなかった。
最終的に参考にしたのはhash_equalsのページ。
このページを見ながら不要な部分を削って自分がわかりやすいようにまとめた。

擬似hash_equals()関数。

function hash_equals($a, $b){
	$res = $a ^ $b;
	$ret = 0;
	for ($i = 0; $i < 60; $i++) {
		$ret += ord($res[$i]);
	}
	return $ret == 0;
}

暗号化された文字列を2つ(DBに格納されているものとユーザが入力したもの)受け取る。
比較演算子の代わりに使うのが「^」。排他的論理和。XOR演算てやつ。
使ったことなかったけどビット演算子のページで理解した。
「&、| そして ^ 演算子の左右のオペランドが文字列の場合、その演算は、 文字列を構成する文字の ASCII 値を使って行います。その結果は文字列になります。」
これに該当する。
「echo "hallo" ^ "hello"; // 出力は、ascii コード #0 #4 #0 #0 #0」てとこでしっくりきた。
差異があるのは2文字目のaとe。ASCIIコード(十進数)でaが97、eが101。差の4が出力される。他の文字は差異がないため0。
ということはまったく同じ文字列同士の場合は全部0。
つまり全部足して0なら一致、1以上なら不一致。
文字列のままだと足せないのでord()関数を使って1文字ずつ数値(ASCIIコード)にして足してる。
比較演算子を使うことなく、内容に関わらず一定の処理時間でパスワードチェックをすることができた。
ループ回数が60固定なのはBlowfishでしか使う予定がないから。

動作は確認したけど計測はしてない。
暇な時に検証しないと_(:3 」∠)_

SHARE