5

ここ数年、PHP のパスワード ストレージを安全にする方法について、stackoverflow で質問しました。主な答えは、次のハッシュアルゴリズムを使用することを提案しています:

function hash_password($password, $nonce) {
  global $site_key;
  return hash_hmac('sha512', $password . $nonce, $site_key);
}

答えは、ランダムナンスを使用することを提案しています。単純な一意のナンスよりもランダムなナンスを持つことに利点はありますか?

たとえば、各ユーザーは変更されない独自の ID を持つことができます。ただし、ユーザー ID はシーケンシャル (MySQL の自動インクリメント機能で作成) であり、ランダムではないと仮定しましょう。ユーザー ID はナンスとして適切でしょうか、それともランダム性は重要ですか?

これで、各ユーザーがユーザー名を選択できるようになりました。各ユーザーには変更されない独自のユーザー名があり、2 人の異なるユーザーが同じユーザー名を持つことはできません。ユーザー名はまだランダムではありませんが、シーケンシャルでもありません。ユーザー名はノンスとして十分でしょうか? ユーザーIDを使用するよりも良いでしょうか?

4

3 に答える 3

2

このトピックについてオンラインで書かれたかなり素晴らしいチュートリアルがあることがわかりました。グーグルのどこで見つけたのかよく覚えていませんが、目の前にあるので、関数を自分で十分に分解できるかどうか見てみましょう...

最初の関数は、任意のサイズのキーの長さを作成できます。私はそれをかなり重くコメントする自由を取りました...

function pbkdf2($password,$salt,$iter_count = 1500,$key_length = 32,$algorithm = 'sha512') 
{
    /*
      @param string password -- password to be encrypted
      @param string salt -- salt to encrypt with
      @param int iter_count -- number of times to iterate blocks
      @param key_length -- length of key to return
      @param $algorithm -- algorithm to use in hashing

      @return string key
    */

    //determine the length of the hahs
    $hash_length = strlen(hash($algorithm,NULL,TRUE));
    //determine the number of key blocks to compute
    $key_blocks = ceil($key_length/$hash_length);
    //initialize key
    $key = '';

    //create the key itself
    //create blocks
    for($block_count = 1;$block_count <= $key_blocks;$block_count++)
    {
        //initalize hash for this block
        $iterated_block = $block = hash_hmac($algorithm,$salt.pack('N',$block_count),$password,TRUE);
        //iterate blocks
        for($iterate = 1;$iterate <= $iter_count;$iterate++)
        {
            //xor each iterate
            $iterated_block ^= ($block = hash_hmac($algorithm,$block,$password,TRUE));
        }
        //append iterated block
        $key .= $iterated_block;
    }
    //return the key
    return substr($key,0,$key_length);
}
  1. 最初に行うことは、ハッシュの長さを把握することです。
  2. 次に、指定されたキーの長さに必要なキー ブロックの数を決定します。
  3. 次に、ハッシュ (キー) を初期化して返す
  4. 各ブロックを作成する for ループを設定します
  5. ソルトに追加されたバイナリのブロックカウンターでブロックの初期ハッシュを取得します
  6. ブロックを $iter_count 回反復するループを開始します (それ自体のハッシュを作成します)
  7. 各反復を XOR し、それを $iterated_block に追加します (以前のハッシュを現在のハッシュに xor します)
  8. XOR ループの終了
  9. 各ブロックの $key に $iterated_block を追加
  10. ブロックループ終了
  11. 鍵を返す

これがおそらくこれを行うための最良の方法だと思います。多分私はあまりにも妄想的ですか?

于 2011-01-13T19:46:05.077 に答える
2

これはすべて、ノンスがソルトであるという仮定に基づいています...

ノンスで塩を意味する場合は、そうです。それには、より多くのレインボーテーブルを作成する必要があります. 通常は 20 文字を超えるソルトで十分ですが、極端なセキュリティ条件では、パスワードごとに新しいランダムなソルトが必要になります。

スローハッシュhttp://www.php.net/manual/en/function.hash.php#89574、皮肉なしでも良い選択です。しかし、私はripemdが好きです。

回答の下半分が表示されませんでした。詳しく説明すると、ノンスはレインボー テーブルの使用を防ぐために使用されます。ID が機能するかどうかは、単に ID の長さに依存します。ランダム性は技術的に重要ではありませんが、より多くのレインボー テーブルが必要になるだけです。例として、"a" という文字を nonce として使用し、パスワードが 2 文字だったとします。a-aa、a-ab、a-ac などのレインボー テーブルを作成する必要があります。毎回ランダムなものを使用する場合、おそらく「a」のすべての順列 + 他のランダム文字のすべての順列を実行する必要があります。

しかし、一般的にレインボー テーブルの作成にはかなりの時間がかかります。したがって、長いソルトを思いついた場合、そのソルトのレインボー テーブルは存在しない可能性があります。

于 2011-01-08T18:15:33.060 に答える
0

使用するのに十分なパスワードを保存するには:

sha512(salt + password)

saltユーザーごとにランダムで一意である必要があります。ランダム ソルトは、事前計算されたハッシュ テーブルへの攻撃を不可能にします。各ユーザーは、独自の計算されたハッシュ テーブルを必要とします。ランダムなソルトを使用しない場合は、事前計算されたテーブルが存在する可能性が高くなります。

パスワードの前にソルトを配置すると、一部のユーザーが同じパスワードを使用している場合にハッシュ パターンを隠すのに役立ちます。

ノンスはリプライ攻撃を防ぐためなので不要です。この保護は、アーキテクチャでは不可能です。

衝突を防ぐためにHMACを使用しても意味がありません。なぜなら、a) MAC ではなくハッシュを使用し、b) SHA-512 の衝突確率を 50% にするには、約 2^256 の値を計算する必要があるためです。そして 2^256 はまさに天文学的な数です。

于 2011-01-08T21:03:26.167 に答える