はじめに
同じハッシュアルゴリズムを採用してる場合、同じデータは必ず同じハッシュ値になります。
これはもちろん一方向ハッシュのメリットなのですが、ログインが必要なサイトでパスワードをハッシュして保存してる場合など、そのままだとよろしくない。
なぜよろしくないか
- aさんとbさんがたまたまXというパスワードを用いた場合に同じハッシュとなる。
- aさんのパスワードが判明したら自動的にbさんのパスワードが判明する。
- もしくはXというパスワードとYというパスワードが同じハッシュ値を得る場合でも片方がわかればもう片方のパスワードが判明したことと同じになる
対策
そこで、ハッシュしたいデータにランダムなデータを追加した物をハッシュし、ランダムなデータはハッシュ値の頭にでも追加するようにしておきます。
以下、PHPによるサンプルです。
hash-test.php
<?php
$hash = makeHash();
var_dump("hash: {$hash}");
var_dump('verify: '.(verify($hash) ? 'true' : 'false'));
function makeHash()
{
$salt = random_int(0, 65535);
$hash = sprintf("%04x", $salt).md5($salt.date('Y-m-d'));
return $hash;
}
function verify($hash)
{
$salt = substr($hash, 0, 4);
$salt = hexdec($salt);
$hash = substr($hash, 4);
return $hash === md5($salt.date('Y-m-d'));
}
これを実行すると以下のようになり、同一日付で実行している限り、同じデータでもハッシュ値は異なり、さらに照合は正しく行われることが確認できました。
$ php hash-test.php
string(42) "hash: a90af0b9e2bbd0816ef8770ddf23867be8e2"
string(12) "verify: true"
$ php hash-test.php
string(42) "hash: b03c7eab59127e732f142d0d0abf5093a64d"
string(12) "verify: true"
$ php hash-test.php
string(42) "hash: 61cca0c2296cc8492214b5c8275d43060bd2"
string(12) "verify: true"
$ php hash-test.php
string(42) "hash: 116dda65929e79f330d3149e4773ec85b1e2"
string(12) "verify: true"
実は
PHPの場合はpassword_hashという便利な関数がありますので、それを利用しましょう。