9

我正在用 php 5.4 开发一个站点,我想知道哪个更好地用于生成随机盐以确保密码安全?

$salt = sha1(openssl_random_pseudo_bytes(23));

或者

$seed = '';
$a = @fopen('/dev/urandom','rb');
$seed .= @fread($a,23);
$salt = sha1(seed);

还是我应该选择:

$salt =  openssl_random_pseudo_bytes(40);

或者

$salt = '';
$a = @fopen('/dev/urandom','rb');
$salt .= @fread($a,23);
4

3 回答 3

10

在实践中,几乎可以肯定没有区别。

两者都openssl_random_pseudo_bytes提供/dev/urandom加密安全的伪随机字节源。两者都不能保证是真正随机的,但在实践中,通过任何已知或可预见的技术,两者都有望与真正的随机性无法区分。

Kmkaplan 指出/dev/urandom在某些条件下可以返回理论上可预测的输出,这在技术上是正确的,如下所述man unrandom

“从/dev/urandom设备读取不会阻塞等待更多熵。因此,如果熵池中没有足够的熵,则返回的值理论上容易受到驱动程序使用的算法的加密攻击.如何做到这一点的知识在当前的非机密文献中是不可用的,但理论上可能存在这样的攻击。如果这是您的应用程序中的一个问题,请改用/dev/random

但是,正如OpenSSL 文档openssl_random_pseudo_bytes中所指出的(在内部调用OpenSSL 函数),实际上也是如此:RAND_pseudo_bytes

"RAND_pseudo_bytes()num个伪随机字节放入bufRAND_pseudo_bytes()如果由但通常不用于密钥生成等。”

这些警告实际上都不应该吓到你使用这些方法——它们描述的弱点只是理论上的,除非可能在某些人为的情况下(例如在启动后立即没有硬件 RNG 的无盘嵌入式设备上),并且不应该在通常部署 PHP 的情况下具有实际问题。

结果是,这些随机数生成方法都不会成为密码系统中最薄弱的环节,因此您可以安全地选择其中任何一种。如果您感到偏执,甚至可以同时使用两者。


附言。一个优点openssl_random_pseudo_bytes是它也可以在 Windows 上运行。另一方面,/dev/urandom即使没有安装 OpenSSL PHP 扩展,它也可以在 Unix 上使用。因此,为了获得最大的可移植性,您确实应该实现对两者的支持。

此外,请始终检查您是否确实收到了与预期一样多的字节;例如,您上面问题中的基于代码可能会在不存在/dev/urandom的 Windows 等系统上静默返回一个空字符串。/dev/urandom

于 2012-12-30T10:23:52.820 回答
10

出于安全目的,您最好使用openssl_random_pseudo_bytes. OpenSSL 负责收集足够的熵来为您提供良好的随机性。/dev/urandom被设计为永远不会阻塞,并且可能会被欺骗给你不那么随机的字节。

对于随机字节,您不需要通过 SHA1 运行它们。

总而言之,请执行以下操作:

$salt = openssl_random_pseudo_bytes(40, $cstrong);
if (! $cstrong) {
    exit('This should not happen');
}
于 2012-12-30T09:02:51.800 回答
0

我知道这是一篇旧帖子,但如果有人偶然发现这里是一个简单的解决方案:

compat_random.php
https://gist.github.com/anzz1/29a787fac8ef6d693b41779911287505

<?php
  require_once(dirname(__FILE__) . '/compat_random.php');

  $salt = random_bytes(40);
?>

完毕。

compat_random.php 只有 2KB,62 行代码。
您应该能够将它与任何 PHP 版本一起使用。

它按以下顺序检查这些函数:

  • random_bytes (PHP >= 7) [密码安全]
  • openssl_random_pseudo_bytes (OpenSSL) [加密安全]
  • mcrypt_create_iv (php_mcrypt) [密码安全]
  • /dev/urandom(UNIX 系统)[密码安全]

您很可能确实有其中一个可用,但如果您没有,它最终会回落到

  • mt_rand() (PHP >= 4) [密码不安全,但在大多数情况下都很好]
  • rand() [不安全]
于 2022-02-03T06:40:04.833 回答