web-dev-qa-db-ja.com

mt_Rand()はソルトの生成に適していますか?

新しいパスワードを保存するためのランダムなフグの塩を生成するために、次のコードを実行する必要があると仮定します。

$blowfishCharacters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789./';
$salt = '';
$type = '2a';
$cost = '08';

$maxIndex = strlen($blowfishCharacters) - 1;

for ($i = 0; $i < 22; $i++) {
        $salt .= $blowfishCharacters[mt_Rand(0, $maxIndex)];
}

$salt = '$' . $type . '$' . $cost . '$' . $salt;
$pass = crypt($password, $salt);

私はこのトピックに関するいくつかの議論を読みましたが、それらはすべて異なる結果に至りました。 mt_Randは常に優れているようですが、この目的に適していますか?

3
Zwirbelbart

ソルトは完全にランダムである必要はなく、ユーザーごとに一意である必要があります。詳細については、Crypto.SEの この質問 を参照してください。そのため、一部のWebサイトはユーザー名を使用してソルトを派生させます(つまり、_$salt=$username.$signup_date_)。

あなたの場合、cryptが 'blowfish hash'と言うとき、それは本当に bcrypt を意味するので、- keepムーアの法則に合わせて コスト係数を選択するとき。


私があなたのコードで行ったいくつかの観察があります。まず、 strlen() の最後にNULL文字が含まれないため、strlen($blowfishCharacters) - 1;は、saltに_/_が表示されないようにします。配列を構築するときは range() を使用することもお勧めしますが、それは私の個人的な好みです。ホイールの再発明はしたくないので、ループを完全になくすこともできます(右?)。したがって、コードは次のようになります。

_$salt=array_merge(range('a', 'z'), range('A', 'Z'), ['.', '/']); //generate the dictionary
shuffle($salt);
$salt=array_slice($salt, 0, 21); //cut to size
_

これは、21個の要素を持つ_$salt_配列を返します。 cryptが必要とする22番目の要素 実際には区切り文字_$_ です。


元の質問に答えるには mt_Rand()のmanページ によると

デフォルトでは、PHPは、Rand()関数でlibc乱数ジェネレータを使用します。mt_Rand()関数は、これのドロップイン置換です。これは、既知の特性を持つ乱数ジェネレータを使用します。 "Mersenne Twister は、平均的なlibc Rand()が提供するものより4倍速く乱数を生成します。

そのため、「安全」ではなく、実行速度が速くなります。


結論として、あなたは塩を導出するために暗号グレードのPRFを必要としない。これは、ソルトが事前に計算されたハッシュテーブルを保護するためです。ソルトがない場合、攻撃者はテーブルを事前に生成し、データベース全体と比較して一致を見つけることができます。ソルトは、攻撃者がデータベース内でそのプロセス各エントリに対してを実行する必要があることを確認します。したがって、十分に高いコスト係数で攻撃を非常に高価にします。

もちろん、コストtooを高く設定すると、多数のユーザーが同時にログインしようとするとサーバーが苦労しますが、私はいつでもセキュリティの不便さのリスクを犠牲にしています。

だからあなたの質問への答えは はいmt_Rand()で十分です

編集:この記事 はbcryptの衛生に関する優れたガイドです。引用セクション#2、

完璧なソースは/ dev/urandomです。他のソースは、MCRYPT_DEV_URANDOMと組み合わせた場合、mcrypt_create_ivになります。どちらも使用できない場合は、openssl_random_pseudo_bytesまたはmt_Rand(最後の手段として)にフォールバックできます。

そうuse _mcrypt_create_iv_ 代わりに.

5
rath

ほとんどの状況では、ソルトは一意である必要があり、暗号的に予測できないものではありません。

したがって、その場合は、RNGが適切にシードされている限り、はい。塩の品質を改善するためのもう1つの一般的な手法は、現在の時刻に乱数を連結し、それをハッシュし(たとえば、SHA1)、テキストでエンコードし(たとえば、base64)、最初のもの[〜#〜 ] n [〜#〜]文字。そこでの衝突の可能性はかなりスリムです。

説明を編集
これが、このテクニックの内容とその理由の説明です。

  • 現在の時刻は、繰り返しを防止します。 2つの塩が同時に生成されない限り、それらは同じにはなりません
  • 乱数は予測可能性を妨げます。ランダム性の要素があるため、前もってソルトを知ることはできません。これは明らかに、乱数が容易に予測できず、現在の時刻に基づいていないことを前提としています。さらに重要なことに、2つの塩が同時に生成された場合の衝突を防ぐのにも役立ちます。
  • ハッシュは分布を平滑化するため、各ビットが設定される可能性は等しくなります。また、結果を見ただけでは、何がソルトを生成するのかを知ることができません。
  • ソルト値を予測する人々に偏執的である場合は、ハッシュの入力に秘密の文字列を連結することもできます。ただし、気にする必要はありません。
7
tylerl