在PHP中,最好的方法生成一个32字节的加密安全盐是什么,而不依赖于在典型PHP安装中很少包含的库?
通过一些谷歌搜索,我发现mt_rand
被认为不够安全,但是我没有找到替代建议。有一篇文章建议从/dev/random
读取,但这不仅不适用于Windows;而且速度非常慢。
我希望在安全性和速度之间取得合理的平衡(也就是说,它不应该像/dev/random
通常那样花费20秒来生成512字节)。
在PHP中,最好的方法生成一个32字节的加密安全盐是什么,而不依赖于在典型PHP安装中很少包含的库?
通过一些谷歌搜索,我发现mt_rand
被认为不够安全,但是我没有找到替代建议。有一篇文章建议从/dev/random
读取,但这不仅不适用于Windows;而且速度非常慢。
我希望在安全性和速度之间取得合理的平衡(也就是说,它不应该像/dev/random
通常那样花费20秒来生成512字节)。
在PHP 7中更容易实现:
只需使用$salt = random_bytes($numberOfDesiredBytes);
生成盐即可。
那么,你为什么需要盐呢?如果是用于密码的话,只需使用password_hash()
和password_verify()
即可。
password_hash
的提醒。结果证明它对我比原来的解决方案更有效。 - user2286243注意:PHP 7.1中
mcrypt
已被弃用。 跳转到最新答案。
您可能需要查看mcrypt_create_iv()
的文档(和注释)。
注意:在PHP 7.1中,
mcrypt
已被弃用。 查看最新答案。
您可以使用函数mycrypt_create_iv()
,自PHP版本5.3以来它也使用Windows服务器上的随机源(不仅限于Unix)。在使用之前,应检查常量MCRYPT_DEV_URANDOM
是否定义。
mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
与random不同,如果没有足够的熵可用,urandom不会阻塞服务器。由于密码盐应该是唯一的(不一定是随机的),我认为urandom是一个很好的选择。
MCRYPT_DEV_URANDOM
是默认值 - 因此,如果您不想更改它,您可以使用mcrypt_create_iv($length)
。此外,此功能是在mcrypt
扩展中实现的,该扩展可能已安装或未安装在您的服务器上。最后,该函数的结果是一个二进制字符串,通常不是您所需的,因为您希望保存盐以供以后引用。我通常在使用盐之前对结果进行base64_encode
编码。 - Gusspassword_hash()
的一个原因是我没有实现密码。我需要一个盐来实现无状态的“API密钥”样式授权协议。 - Gussuniqueid
不适合生成随机字符串,因为它也是基于 microtime
的。CPU 循环通常比微秒滴答短得多,这可能会导致在循环内给定变量的可能一致性。将第二个参数“熵”设置为 true,
uniqid('', true)
将提供更高的随机性。
要获得一个与大多数字符集兼容的随机字符串,可以对mcrypt_create_iv
函数的初始化向量应用base64编码:mcrypt
$length = 16;
base64_encode(mcrypt_create_iv(ceil(0.75*$length), MCRYPT_DEV_URANDOM))
//> hlZuRJypdHFQPtI2oSFrgA==
strlen(base64_encode(mcrypt_create_iv(ceil(0.75*$length), MCRYPT_DEV_URANDOM)))
//> 16
将字符字母表减少到2^6Bit会增加大小,这在上述中已经说明。
从/dev/urandom
读取,或使用openssl_random_pseudo_bytes()
。
看起来这个问题已经有了一个被接受的答案,但在一番研究和阅读后,我想额外指出如果你不想把所有的鸡蛋放在一个篮子里,你可能需要增加一些安全性。
我建议不要仅仅依赖PHP来创建你的盐并对密码进行哈希。如果你让数据库完成部分工作,你可以更加混淆你的解决方案。
有人建议仅使用password_hash()和password_verify()。虽然这些都是很好的方法,但我强烈建议还要加入盐的概念。
回答这个问题,盐可以是任何真正随机且唯一的东西。只要你遵守这两条规则,你可以按照任意方式生成它。
一些不错的资源:
https://www.codeproject.com/Articles/704865/Salted-Password-Hashing-Doing-it-Right https://auth0.com/blog/adding-salt-to-hashing-a-better-way-to-store-passwords/
uniqid() 对于这个目的应该是可以的。
我认为microtime()
就足够了。
奇怪的是,我仍然因为这个答案而被踩。
尽管我得到的唯一解释是microtime是可预测的。
对我来说,这听起来很奇怪,因为盐总是被认为是公开已知的 - 所以根本没有预测的用处。
echo microtime()
通过一个for循环(10个循环就可以了),看看你有多错... - Mike S
/dev/urandom
可以用于更快的生成,但在 Windows 系统上仍无法使用。 - Amber