ハッシュ関数は、同じ入力文字列に対して常に同じ値を返します。私のユーザー (Alice) がパスワードを持っているとしましょうsecret
。secret
を使用したハッシュmd5()
は、次のハッシュにつながります
5ebe2294ecd0e0f08eab7690d2a6ee69
辞書 (一般的な単語とパスワードのリスト) またはそのサービスを提供するさまざまなサイトの 1 つを使用して、攻撃者 (Mallory) は自分の辞書に5ebe2294ecd0e0f08eab7690d2a6ee69 = secret
.
ハッシュする前にソルトするプロセスにより、ソルトを知らずに辞書攻撃を使用することが難しくなります。次の点を考慮してください。
<?php
$salt = '@!#%$@#$@SADLkwod,sdaDwqksjaoidjwq@#@!';
$hash = md5($salt . 'secret');
結果のハッシュは nowb58ad809eece17322de5024d79299f8a
ですが、Alice のパスワードはまだsecret
です。マロリーがソルトハッシュを手に入れたとしても、彼女の辞書に答えが見つからない可能性があります. もしそうなら、辞書は彼女に間違った答えを与えるでしょう.
データベースに静的ソルトを保存しないでください。アプリケーションの構成とともに保存することをお勧めします (ちなみに、Web からは使用できません)。
動的ソルトを使用する場合は、データベースを使用する必要があります。既存の有効なデータの null 以外の列を使用してソルトを構築します (秘密の暗号化キーに基づくフグ暗号化されたユーザー名の文字列は、通常、暗号的に安全です)。塩には別のカラムを使用しないでください。既存の列を使用できない場合は、ソルトをハッシュと同じ列に組み込みます。たとえば、最初の 32 文字を 128 ビットのソルトに使用し、最後の 40 文字を 160 ビットのハッシュに使用します。次の関数は、そのようなハッシュを生成します。
function seeded_sha1($string, $seed_bits) {
if(($seed_bits % 8) != 0) {
throw new Exception('bits must be divisible by 8');
}
$salt = '';
for($i = 0; $i < $seed_bits; $i+=8) {
$salt .= pack('c', mt_rand());
}
$hexsalt = unpack('h*hex', $salt);
return $hexsalt['hex'] . sha1($salt . $string);
}
function compare_seeded_sha1($plain, $hash) {
$sha1 = substr($hash, -40);
$salt = pack('h*', substr($hash, 0, -40));
$plain_hash = sha1($salt . $plain);
return ($plain_hash == $sha1);
}
攻撃者が SQL インジェクションを使用してデータベースに侵入した場合、攻撃者はアプリケーション構成にアクセスできないため、少なくとも取得したハッシュは役に立ちません。サーバーがルート化されると、何をしてもほとんどゲームオーバーです。
注:md5()
たとえば、より安全なハッシュ アルゴリズムを使用する理由として、他の種類の攻撃が考えられsha1()
ます。または、さらに良いのは、セキュリティを考慮して設計され、ほぼすべての PHP バージョンと下位互換性があるポータブル PHP パスワード ハッシュ フレームワークを使用することです。
require('PasswordHash.php');
$pwdHasher = new PasswordHash(8, FALSE);
// $hash is what you would store in your database
$hash = $pwdHasher->HashPassword( $password );
// $hash would be the $hashed stored in your database for this user
$checked = $pwdHasher->CheckPassword($password, $hash);
if ($checked) {
echo 'password correct';
} else {
echo 'wrong credentials';
}