如何产生良好的盐 - 我的功能足够安全吗?

JDe*_*age 38 php security salt

这是我用来生成随机盐的函数:

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

这是针对非商业网站的.它仅用于生成salt(存储在db中并与用户提交的pw一起用于散列).

这个合适吗?我应该使用更大的字符子集,如果是这样,在PHP中有一个简单的方法吗?

fre*_*ley 43

如果您正在散列密码,则应使用现代哈希算法,该算法不需要您生成自己的盐.使用弱哈希算法会对您和您的用户造成危险.我的原始答案是八年前写的.时代已经改变,密码散列现在变得容易多了.

您应该始终使用内置函数来散列/检查密码.在任何时候使用您自己的算法都会带来大量不必要的风险.

对于PHP,请考虑使用password_hash()PASSWORD_BCRYPT算法.没有必要提供自己的盐.

以下是我原来的答案,为后人:


警告:根据uniqid的文档,以下实现不会产生不可预测的salt .

php sha1页面:

$salt = uniqid(mt_rand(), true);
Run Code Online (Sandbox Code Playgroud)

这看起来比您提出的更简单,更有效(因为每个都是唯一的).


kij*_*jin 18

如果你在Linux上,/dev/urandom可能是你最好的随机源.它由操作系统本身提供,因此它保证比任何PHP内置函数更可靠.

$fp = fopen('/dev/urandom', 'r');
$randomString = fread($fp, 32);
fclose($fp);
Run Code Online (Sandbox Code Playgroud)

这将为您提供32个字节的随机blob.你可能想通过这样的方式来传递base64_encode()它,使它变得清晰.不需要自己玩弄角色.

编辑2014:在PHP 5.3及更高版本中,openssl_random_pseudo_bytes()获取一堆随机字节是最简单的方法.在*nix系统上,它/dev/urandom在幕后使用.在Windows系统上,它使用内置于OpenSSL库中的不同算法.

相关:https://security.stackexchange.com/questions/26206

相关:我应该使用urandom还是openssl_random_pseudo_bytes?


Kri*_*ann 8

password_hash()在PHP 5.5及更高版本中可用.我很惊讶地发现这里没有提到它.

使用password_hash()时,不需要生成salt,因为使用bcrypt算法自动生成salt - 因此无需组成一组字符.

而是使用password_verify()将用户提交的密码与存储在数据库中的唯一密码哈希进行比较.只需将用户名和密码哈希存储在用户数据库表中,您就可以使用password_verify()将其与用户提交的密码进行比较.

密码hash()的工作方式:

在将字符串存储在数据库中时,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 
Run Code Online (Sandbox Code Playgroud)

要验证散列密码,请使用password_verify():

$password_enc = password_hash("goat", PASSWORD_DEFAULT);
dump(password_verify('goat', $password_enc)); // TRUE
dump(password_verify('fish', $password_enc)); // FALSE
Run Code Online (Sandbox Code Playgroud)

如果您愿意,可以手动添加salt作为选项,如下所示:

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

  • 这个答案很好,因为它涵盖了用于生成密码的最新PHP实现.但它没有回答关于如何生成良好盐的问题(有时你明确需要这个,例如用于其他散列目的). (2认同)