PHP 中的安全随机数生成

新手上路,请多包涵

用例:“我忘记了密码”按钮。我们无法找到用户的原始密码,因为它是以散列形式存储的,所以唯一要做的就是生成一个新的随机密码并将其通过电子邮件发送给他。这需要密码学不可预测的随机数,mt_rand 对此不够好,而且通常我们不能假设托管服务将提供对操作系统的访问以安装密码学随机数模块等。所以我正在寻找一种方法在 PHP 本身中生成安全的随机数。

到目前为止我提出的解决方案包括存储一个初始种子,然后对于每个调用,

 result = seed
seed = sha512(seed . mt_rand())

这是基于 sha512 哈希函数的安全性(mt_rand 调用只是为了让获得数据库副本的对手的生活更加困难)。

我错过了什么,还是有更好的解决方案?

原文由 rwallace 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 653
2 个回答

您还可以考虑使用 OpenSSL openssl_random_pseudo_bytes,它从 PHP 5.3 开始可用。

  string openssl_random_pseudo_bytes ( int $length [, bool &$crypto_strong ] )

生成一串伪随机字节,字节数由长度参数确定。它还指示是否使用加密强算法来生成伪随机字节,并通过可选的 crypto_strong 参数执行此操作。这很少为 FALSE,但某些系统可能已损坏或陈旧。

http://www.php.net/manual/en/function.openssl-random-pseudo-bytes.php

由于 PHP 7 还有 random_bytes 可用的功能

string random_bytes ( int $length )

http://php.net/manual/en/function.random-bytes.php

原文由 Eugene Dounar 发布,翻译遵循 CC BY-SA 3.0 许可协议

我强烈建议将 unix 系统上的 /dev/urandom 或 Windows 平台上的 crypto-api 作为密码的熵源。

意识到哈希不是神奇的熵增加设备的重要性我怎么强调都不为过。以这种方式滥用它们并不比在散列之前使用种子和 rand() 数据更安全,我相信您认识到这不是一个好主意。种子抵消了(确定性 mt_rand()),因此即使包括它也毫无意义。

人们认为他们很聪明,他们的劳动结果是脆弱的系统和设备,这些系统和设备将他们系统的安全性和其他系统的安全性(通过糟糕的建议)置于不必要的危险之中。

两个错误并不能构成一个正确。一个系统的强大取决于它最薄弱的部分。这不是允许或借口接受让更多的地方变得不安全。


这是一些用于获取安全随机 128 位字符串的 PHP 代码,来自 Mark Seecof 在 php.net 上的评论

“如果您出于安全或加密目的需要一些伪随机位(egg,用于分组密码的随机 IV,用于密码哈希的随机盐),mt_rand() 是一个糟糕的来源。在大多数 Unix/Linux 和/或 MS-Windows 平台上,您可以获得来自操作系统或系统库的更好等级的伪随机位,如下所示:

 <?php
// get 128 pseudorandom bits in a string of 16 bytes

$pr_bits = '';

// Unix/Linux platform?
$fp = @fopen('/dev/urandom','rb');
if ($fp !== FALSE) {
    $pr_bits .= @fread($fp,16);
    @fclose($fp);
}

// MS-Windows platform?
if (@class_exists('COM')) {
    // http://msdn.microsoft.com/en-us/library/aa388176(VS.85).aspx
    try {
        $CAPI_Util = new COM('CAPICOM.Utilities.1');
        $pr_bits .= $CAPI_Util->GetRandom(16,0);

        // if we ask for binary data PHP munges it, so we
        // request base64 return value.  We squeeze out the
        // redundancy and useless ==CRLF by hashing...
        if ($pr_bits) { $pr_bits = md5($pr_bits,TRUE); }
    } catch (Exception $ex) {
        // echo 'Exception: ' . $ex->getMessage();
    }
}

if (strlen($pr_bits) < 16) {
    // do something to warn system owner that
    // pseudorandom generator is missing
}
?>

注意:在您的代码中同时保留读取 /dev/urandom 和访问 CAPICOM 的尝试通常是安全的,尽管每个都会在对方的平台上默默地失败。将它们都留在那里,这样您的代码将更加可移植。”

原文由 Einstein 发布,翻译遵循 CC BY-SA 3.0 许可协议

推荐问题
logo
Stack Overflow 翻译
子站问答
访问
宣传栏