web-dev-qa-db-ja.com

良い塩を生成する方法-私の機能は十分に安全ですか?

ランダムソルトを生成するために使用している関数は次のとおりです。

function generateRandomString($nbLetters){
    $randString="";
    $charUniverse="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    for($i=0; $i<$nbLetters; $i++){
       $randInt=Rand(0,61);
        $randChar=$charUniverse[$randInt];
        $randString=$randomString.$randChar;
    }
    return $randomString;
}

これは非商用ウェブサイト用です。これは、ソルトを生成するためにのみ使用されます(dbに保存され、ユーザーが送信したハッシュ用のpwと一緒に使用されます)。

これは適切ですか?文字のより大きなサブセットを使用する必要がありますか?使用する場合、PHPでそれを行う簡単な方法はありますか?

37
JDelage

パスワードをハッシュする場合は、独自のソルトを生成する必要のない最新のハッシュアルゴリズムを使用する必要があります。弱いハッシュアルゴリズムの使用は、あなたとあなたのユーザーの両方にとって危険です。私の最初の答えは8年前に書かれました。時代は変わり、パスワードのハッシュ化は今やずっと簡単になりました。

always組み込み関数を使用してパスワードをハッシュ/チェックする必要があります。任意の時点で独自のアルゴリズムを使用すると、大量の不必要なリスクが発生します。

PHPの場合、 password_hash()PASSWORD_BCRYPTアルゴリズムとともに使用することを検討してください。独自の塩を提供する必要はありません。

以下は、後世のための私の最初の答えです:


Warning:次の実装は、 niqid のドキュメントに従って、予測できないソルトを生成しません。

php sha1ページ から:

$salt = uniqid(mt_Rand(), true);

これは、あなたが提案したものよりも単純で、効果的です(それぞれが一意であるため)。

41
fredley

Linuxを使用している場合、_/dev/urandom_がおそらくランダム性の最良のソースです。これはOS自体によって提供されるため、どのPHP組み込み関数よりもはるかに信頼性が高いことが保証されています。

_$fp = fopen('/dev/urandom', 'r');
$randomString = fread($fp, 32);
fclose($fp);
_

これにより、32バイトのランダムBLOBが得られます。おそらく、これをbase64_encode()のようなものに渡して読みやすくすることができます。自分でキャラクターをジャグリングする必要はありません。

2014年の編集:PHP 5.3以上では、openssl_random_pseudo_bytes()は* nixシステムでは、バックグラウンドで_/dev/urandom_を使用し、Windowsシステムでは、OpenSSLライブラリに組み込まれている別のアルゴリズムを使用します。

関連: https://security.stackexchange.com/questions/26206

関連: randomまたはopenssl_random_pseudo_bytesを使用すべきですか?

18
kijin

password_hash() はPHP 5.5以降で利用可能です。ここで言及されていないことを知って驚いています。

Password_hash()を使用すると、bcryptアルゴリズムを使用してソルトが自動的に生成されるため、ソルトを生成する必要がありません。したがって、文字セットを構成する必要はありません。

代わりに、ユーザーが送信したパスワードは、password_verify()を使用してデータベースに保存されている一意のパスワードハッシュと比較されます。ユーザーデータベーステーブルにユーザー名とパスワードハッシュを保存するだけで、password_verify()を使用してユーザーが送信したパスワードと比較できます。

パスワードhash() 'ingの仕組み:

Password_hash()関数は、データベースに文字列を保存するときに一意のパスワードハッシュを出力します。列には最大255文字を使用することをお勧めします。

_$password = "goat";
echo password_hash($password, PASSWORD_DEFAULT);
echo password_hash($password, PASSWORD_DEFAULT);
echo password_hash($password, PASSWORD_DEFAULT);

// Output example (store this in the database)
$2y$10$GBIQaf6gEeU9im8RTKhIgOZ5q5haDA.A5GzocSr5CR.sU8OUsCUwq  <- This hash changes.
$2y$10$7.y.lLyEHKfpxTRnT4HmweDKWojTLo1Ra0hXXlAC4ra1pfneAbj0K
$2y$10$5m8sFNEpJLBfMt/3A0BI5uH4CKep2hiNI1/BnDIG0PpLXpQzIHG8y 
_

ハッシュ化されたパスワードを確認するには、 password_verify() を使用します。

_$password_enc = password_hash("goat", PASSWORD_DEFAULT);
dump(password_verify('goat', $password_enc)); // TRUE
dump(password_verify('fish', $password_enc)); // FALSE
_

必要に応じて、次のようにオプションとして塩を手動で追加できます。

_$password = 'MyPassword';
$salt = 'MySaltThatUsesALongAndImpossibleToRememberSentence+NumbersSuch@7913';
$hash = password_hash($password, PASSWORD_DEFAULT, ['salt'=>$salt]);
// Output: $2y$10$TXlTYWx0VGhhdFVzZXNBT.ApoIjIiwyhEvKC9Ok5qzVcSal7T8CTu  <- This password hash not change.
_
8

別の答えからアドバイスを受けて mt_Rand(0、61) を使用します。これは、Mersenne Twisterがより良いエントロピーを生成するためです。

さらに、関数は実際には2つの部分です。ランダムな$nbLetters数字を生成し、base62でエンコードします。これにより、メンテナンスプログラマー(おそらくあなた!)にとって、物事がはるかに明確になります。

// In a class somewhere
private $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

private function getBase62Char($num) {
    return $chars[$num];
}

public function generateRandomString($nbLetters){
    $randString="";

    for($i=0; $i < $nbLetters; $i++){
        $randChar = getBase62Char(mt_Rand(0,61));
        $randString .= $randChar;
    }

    return $randomString;
}
4
Drew Stephens

Rand(0,61)mt_Rand(0, 61) に置き換えると、問題ないはずです(_mt_Rand_が乱数の生成に優れているため)...

しかし、塩の強さよりも重要なのは、それをハッシュする方法です。優れたソルトルーチンがあり、md5($pass.$salt)のみを実行する場合、ソルトは破棄されます。私は個人的にハッシュを伸ばすことをお勧めします...例えば:

_function getSaltedHash($password, $salt) {
    $hash = $password . $salt;
    for ($i = 0; $i < 50; $i++) {
        $hash = hash('sha512', $password . $hash . $salt);
    }
    return $hash;
}
_

ハッシュストレッチの詳細については、 this SO answer ...をご覧ください。

4
ircmaxell

ここにウィンドウがあり、/ dev/randomができない場合のより良い方法があります。

//Key generator
$salt = base64_encode(openssl_random_pseudo_bytes(128, $secure));
//The variable $secure is given by openssl_random_ps... and it will give a true or false if its tru then it means that the salt is secure for cryptologic.
while(!$secure){
    $salt = base64_encode(openssl_random_pseudo_bytes(128, $secure));
}
2
tor

これは私の方法です。大気ノイズからの真の乱数を使用します。それはすべて、擬似乱数値と文字列と混在しています。シャッフルしてハッシュ化。ここに私のコードがあります:私はそれをやり過ぎと呼びます。

<?php
function generateRandomString($length = 10) {
    $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
    $randomString = '';
    for ($i = 0; $i < $length; $i++) {
        $randomString .= $characters[Rand(0, strlen($characters) - 1)];
    }
    return $randomString;
}

function get_true_random_number($min = 1, $max = 100) {
    $max = ((int) $max >= 1) ? (int) $max : 100;
    $min = ((int) $min < $max) ? (int) $min : 1;
    $options = array(
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HEADER => false,
        CURLOPT_FOLLOWLOCATION => true,
        CURLOPT_ENCODING => '',
        CURLOPT_USERAGENT => 'PHP',
        CURLOPT_AUTOREFERER => true,
        CURLOPT_CONNECTTIMEOUT => 120,
        CURLOPT_TIMEOUT => 120,
        CURLOPT_MAXREDIRS => 10,
    );

    $ch = curl_init('http://www.random.org/integers/?num=1&min='
        . $min . '&max=' . $max . '&col=1&base=10&format=plain&rnd=new');
    curl_setopt_array($ch, $options);
    $content = curl_exec($ch);
    curl_close($ch);

    if(is_numeric($content)) {
        return trim($content);
    } else {
        return Rand(-10,127);
    }
}

function generateSalt() {
    $string = generateRandomString(10);
    $int = get_true_random_number(-2,123);
    $shuffled_mixture = str_shuffle(Time().$int.$string);
    return $salt = md5($shuffled_mixture);
}

echo generateSalt();
?>

大気ノイズはrandom.orgによって提供されます。また、色相と位置を介して解釈される溶岩ランプの画像からの真にランダムな生成を見てきました。 (色は場所です)

2
user3483494

私はこれを使用します:

$salt = base64_encode(mcrypt_create_iv(PBKDF2_SALT_BYTES, MCRYPT_DEV_URANDOM));
1
William Wallace

かなり簡単なテクニック:

$a = array('a', 'b', ...., 'A', 'B', ..., '9');
shuffle($a);
$salt = substr(implode($a), 0, 2);  // or whatever sized salt is wanted

Uniqid()とは異なり、ランダムな結果を生成します。

1
Jay

たとえば、非常に良いソルトはユーザー名だと思います(pwハッシュについて話していて、ユーザー名が変わらない場合)。

何も生成する必要も、データをさらに保存する必要もありません。

1
NikiC

最終的な一意のソルトが必要な場合は、入力した電子メールやユーザー名などのユーザーが必要とする一意の値を使用し、sha1を使用してハッシュし、コードで生成されたソルト値と結合(連結)する必要があります。

別の方法として、$charUniverseなどの特殊文字を使用して@,!#-を拡張する必要があります。

0
SaidbakR