15

パスワード取得トークンを作成する際のソルトとして使用されるサイト全体のハッシュを作成したいと思います。私はこれを行うための最良の方法の感覚を得ようとしてstackoverflowの周りを跳ね回っています。

リセットプロセスは次のとおりです。

ユーザーがパスワードのリセットメールをリクエストすると、コードは取得トークンを生成します。

$token = hash_hmac('sha256', $reset_hash* , $site_hash)

* $ reset_hashは、phpass HashPassword()関数を使用して作成されたハッシュであり、ユーザーテーブルに保存されます。

次に、URLでトークンをユーザーの電子メールアドレスに送信します。トークンが1時間でタイムアウトする前にクリックします。私は彼らの提出物を、サーバー側で生成されたチャレンジトークンと照合します。一致する場合は、新しいパスワードを選択してからログインする必要があります。

$site_keyを生成する最良の方法を知りたいです。乱数がシードされた別のHMACハッシュを使用することを考えています。

$site_key = hash_hmac('sha256', MCRYPT_DEV_RANDOM, MCRYPT_DEV_RANDOM);

これにより、次のようなものが生成されます。

98bb403abbe62f5552f03494126a732c3be69b41401673b08cbfefa46d9e8999

これは、この目的に使用するのに適したランダムですか?私はこれを複雑にしすぎていますか、それとも間違った方法でアプローチしていますか?

私はこの答えによってHMACを使用するように促されました

編集:私は同僚の何人かによって促された「秘密の質問」のステップを避けようとしているので、パスワードをリセットするための単一のステップを提供するリセットリンクが欲しいです。したがって、私の懸念は、このプロセスが機密情報を含むシステムを保護するのに十分安全であるということです。

解決済み、今のところ:TheRookがリセットトークンとして説明しているように、ナンスを使用します。コメントとフィードバックをありがとうございました。

4

1 に答える 1

24

そもそも、あなたは塩について話していません。あなたはCryptographicNonceについて話しているので、パスワードをソルトするときはCryptographicNonceを使用する必要があります。パスワードをリセットする場合は、データベースに保存されている乱数である必要があります。「サイトソルト」を持つことは有利ではありません。

何よりもまず、 uniqid()は時間のかかる計算であり、時間は非常に弱いシードであるため、私は好きではありません。 rand()vs mt_rand()、スポイラー:rand()は完全ながらくたです。

Webアプリケーションでは、安全なシークレットの優れたソースは、などのエントロピープールへの非ブロッキングアクセス/dev/urandomです。PHP 5.3以降、PHPアプリケーションはを使用できopenssl_random_pseudo_bytes()、Opensslライブラリはオペレーティングシステムに基づいて最適なエントロピーソースを選択します。Linuxでは、これはアプリケーションがを使用することを意味します/dev/urandom。スコットからのこのコードスニップはかなり良いです:

function crypto_rand_secure($min, $max) {
        $range = $max - $min;
        if ($range < 0) return $min; // not so random...
        $log = log($range, 2);
        $bytes = (int) ($log / 8) + 1; // length in bytes
        $bits = (int) $log + 1; // length in bits
        $filter = (int) (1 << $bits) - 1; // set all lower bits to 1
        do {
            $rnd = hexdec(bin2hex(openssl_random_pseudo_bytes($bytes)));
            $rnd = $rnd & $filter; // discard irrelevant bits
        } while ($rnd >= $range);
        return $min + $rnd;
}

function getToken($length=32){
    $token = "";
    $codeAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    $codeAlphabet.= "abcdefghijklmnopqrstuvwxyz";
    $codeAlphabet.= "0123456789";
    for($i=0;$i<$length;$i++){
        $token .= $codeAlphabet[crypto_rand_secure(0,strlen($codeAlphabet))];
    }
    return $token;
}
于 2010-07-20T15:36:00.777 に答える