如何生成好的盐 - 我的函数足够安全吗?
这是我用来生成随机盐的函数:
function generateRandomString($nbLetters){
$randString="";
$charUniverse="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
for($i=0; $i<$nbLetters; $i++){
$randInt=rand(0,61);
$randChar=$charUniverse[$randInt];
$randString=$randomString.$randChar;
}
return $randomString;
}
这是一个非商业网站。它仅用于生成盐(存储在数据库中并与用户提交的密码一起用于哈希)。
这合适吗?我应该使用更大的字符子集吗?如果是的话,在 PHP 中是否有一种简单的方法可以做到这一点?
Here's the function I'm using to generate random salts:
function generateRandomString($nbLetters){
$randString="";
$charUniverse="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
for($i=0; $i<$nbLetters; $i++){
$randInt=rand(0,61);
$randChar=$charUniverse[$randInt];
$randString=$randomString.$randChar;
}
return $randomString;
}
This is for a non commercial website. It's only used to generate the salt (to be stored in the db and used along with the user submitted pw for hashing).
Is this appropriate? Should I use a larger subset of characters, and if so is there an easy way to do that in PHP?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(11)
如果您要对密码进行哈希处理,则应该使用现代哈希算法,该算法不需要您生成自己的盐。使用弱哈希算法会给您和您的用户带来危险。我原来的答案是八年前写的。时代已经变了,密码散列现在变得容易多了。
您应该始终使用内置函数来散列/检查密码。任何时候使用自己的算法都会带来大量不必要的风险。
对于 PHP,请考虑使用 password_hash(),其中
PASSWORD_BCRYPT
算法。无需提供自己的盐。以下是我的原始答案,供后代使用:
从 php sha1 页面:
这看起来更简单,也更有效(因为每个都是独特)比你所提议的。
If you are hashing passwords, you should use a modern hashing algorithm that does not require you to generate your own salt. Using weak hashing algorithms presents a danger to both you and your users. My original answer was written eight years ago. Times have changed, and password hashing is a lot easier now.
You should always use built in functions to hash/check passwords. Using your own algorithms at any point introduces a huge amount of unnecessary risk.
For PHP, consider using password_hash(), with the
PASSWORD_BCRYPT
algorithm. There is no need to provide your own salt.Below is my original answer, for posterity:
From the php sha1 page:
This looks simpler, and more effective (since each is unique) than what you have proposed.
如果您使用的是 Linux,
/dev/urandom
可能是最好的随机源。它由操作系统本身提供,因此保证比任何 PHP 内置函数都要可靠得多。这将为您提供 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?
If you're on Linux,
/dev/urandom
is probably your best source of randomness. It's supplied by the OS itself, so it's guaranteed to be much more reliable than any PHP built-in function.This will give you 32 bytes of random blob. You'll probably want to pass this through something like
base64_encode()
to make it legible. No need to juggle characters yourself.Edit 2014: In PHP 5.3 and above,
openssl_random_pseudo_bytes()
is the easiest way to get a bunch of random bytes. On *nix systems, it uses/dev/urandom
behind the scenes. On Windows systems, it uses a different algorithm that is built into the OpenSSL library.Related: https://security.stackexchange.com/questions/26206
Related: should i use urandom or openssl_random_pseudo_bytes?
password_hash()
在 PHP 5.5 中可用和更新的。我很惊讶地发现这里没有提到它。使用password_hash(),不需要生成盐,因为盐是使用bcrypt算法自动生成的——因此不需要组成一组字符。
相反,使用password_verify() 将用户提交的密码与存储在数据库中的唯一密码散列进行比较。只需将用户名和密码哈希存储在用户数据库表中,然后您就可以使用password_verify() 将其与用户提交的密码进行比较。
密码 hash() 的工作原理:
将字符串存储在数据库中时,password_hash() 函数会输出唯一的密码哈希 - 建议该列最多允许 255 个字符。
要验证哈希密码,请使用
password_verify()
< /a>:如果您愿意,可以手动添加盐作为选项,如下所示:
password_hash()
is availble in PHP 5.5 and newer. I am surprised to learn it is not mentioned here.With password_hash() there is no need to generate a salt as the salt is automatically being generated using the bcrypt algorithm -- and therefore no need to make up a set of characters.
Instead, the user-submitted password is compared to the unique password hash stored in the database using password_verify(). Just store Username and Password hash in the user database table, you will then be able to compare it to a user-submitted password using password_verify().
How password hash()'ing works:
The password_hash() function outputs a unique password hash, when storing the string in a database -- it is recommended that the column allows up to 255 characters.
To verify a hashed password, you use
password_verify()
:If you prefer, salt can be added manually as an option, like so:
将
rand(0,61)
替换为 < code>mt_rand(0, 61) 应该没问题(因为mt_rand
更擅长生成随机数)...但比盐的强度更重要的是你散列它的方式。如果您有很好的盐习惯,但只执行
md5($pass.$salt)
,那么您就扔掉了盐。我个人建议拉伸散列...例如:有关散列拉伸的更多信息,请查看 这个答案...
Replace
rand(0,61)
withmt_rand(0, 61)
and you should be fine (Sincemt_rand
is better at producing random numbers)...But more important than strength of the salt is the way you hash it. If you have a great salt routine, but only do
md5($pass.$salt)
, you're throwing away the salt. I personally recommend stretching the hash... For example:For more information on hash stretching, check out this SO answer...
我会从另一个答案中获取建议并使用 mt_rand(0, 61)< /a>,因为梅森扭曲器产生更好的熵。
此外,您的函数实际上由两部分组成:生成随机
$nbLetters
数字并以 base62 对其进行编码。对于几年后偶然发现它的维护程序员(也许是你!)来说,这将使事情变得更加清晰:I would take advice from another answer and use mt_rand(0, 61), because the Mersenne Twister produces better entropy.
Additionally, your function is really two parts: generating random
$nbLetters
digits and encoding that in base62. This will make things much clearer to a maintenance programmer (maybe you!) who stumbles across it a few years down the road:这是我的方法,它使用来自大气噪声的真正随机数。它全部与伪随机值和字符串混合在一起。打乱和散列。这是我的代码:我称之为矫枉过正。
大气噪声由 random.org 提供。我还看到了通过色调和位置解释的熔岩灯图像的真正随机生成。 (色相是位置)
This is my method, It uses truly random numbers from atmospheric noise. It is all mixed in with pseudo-random values and strings. Shuffled and hashed. Here is my code: I call it overkill.
The atmospheric noise is provided by random.org. I have also seen truly random generation from images of lava lamps that are interpreted via hue and location. (Hue is location)
如果您有 Windows 并且无法执行 /dev/random,这是一个更好的方法。
Here is a much better way if you have windows and cant do /dev/random.
我认为一个非常好的盐例如是用户名(如果您正在谈论 pw 哈希并且用户名不会改变)。
您不需要生成任何内容,也不需要存储更多数据。
I think that a very good salt for example is the user name (if you are talking about pw hashing and the user name doesn't change.)
You don't need to generate anything and don't need to store further data.
一种相当简单的技术:
与 uniqid() 不同,它生成随机结果。
A fairly simple technique:
Unlike uniqid() it generates a random result.
我用这个:
I use this:
如果您想要最终的唯一盐,您应该使用用户输入和要求的唯一值(例如电子邮件或用户名),然后使用 sha1 对其进行哈希处理,然后将其与代码生成的盐值合并(连接)。
另外,您必须通过一些特殊字符(例如
@,!#-
等)来扩展$charUniverse
。If you want ultimate unique salt you should use a unique value entered and required by the user such as the email or the username, then hashing it using sha1 and then merge it - concatenate - with the salt value generated by your code.
Another, you have to extend
$charUniverse
by the mean of some special characters such as@,!#-
etc.