在PHP中保护随机数生成

rwa*_*ace 33 php security random hash

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

到目前为止我提出的解决方案涉及存储初始种子,然后为每次调用,

result = seed
seed = sha512(seed . mt_rand())
Run Code Online (Sandbox Code Playgroud)

这是基于SHA512哈希函数的安全性(该mt_rand电话只是为了让生活多一点对谁获得数据库的副本对手困难).

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

Ein*_*ein 59

我强烈建议在unix系统上使用/ dev/urandom或在windows平台上使用crypto-api作为密码的熵源.

我不能强调实现哈希的重要性不是神奇的增加熵的设备.以这种方式滥用它们并不比使用种子和rand()数据在散列之前更安全,我确信你认识到这不是一个好主意.种子取消了(确定性的mt_rand()),所以即使包括它也没有任何意义.

人们认为他们聪明聪明,他们的劳动成果是脆弱的系统和设备,使他们的系统安全和其他系统的安全(通过糟糕的建议)处于不必要的危险之中.

两个错误并不是正确的.一个系统只有它最薄弱的部分一样强大.这不是接受使其更加不安全的许可或借口.


下面是一些PHP代码来获取一个安全的随机128位字符串,来自php.net的评论:Mark Seecof:

"如果你需要一些伪随机位用于安全或加密目的(egg,随机IV用于分组密码,随机盐用于密码散列)mt_rand()是一个很差的来源.在大多数Unix/Linux和/或MS-Windows平台上,你可以获得来自OS或系统库的更好等级的伪随机位,如下所示:

<?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
}
?>
Run Code Online (Sandbox Code Playgroud)

注意:保留读取/ dev/urandom的尝试和代码中访问CAPICOM的尝试通常是安全的,尽管每个都会在另一个平台上无声地失败.把它们留在那里,这样你的代码就会更便携."

  • 更新:从[Windows平台SDK可再发行组件:CAPICOM](http://www.microsoft.com/en-us/download/details.aspx?id=25281) - "从Windows SDK开始,从Windows SDK中排除CAPICOM对于Windows 7,尽管distributable将在32位版本的Windows 7和Windows Server 2008 R2操作系统上运行,但不推荐使用它.有关更多信息,请参阅[使用CAPICOM的替代方法](http:// msdn. microsoft.com/en-us/library/windows/desktop/cc778518%28v=vs.85%29.aspx)" (5认同)
  • @Einstein,为什么不简单地使用`openssl_random_pseudo_bytes`? (5认同)
  • @汤姆,爱因斯坦:鉴于这个问题似乎是谷歌首次在"PHP安全随机"上的结果,我觉得逐字引用代码示例是个好主意,以防链接中断某天. (2认同)

Eug*_*nar 40

您还可以考虑使用OpenSSL openssl_random_pseudo_bytes,它自PHP 5.3起可用.

 string openssl_random_pseudo_bytes ( int $length [, bool &$crypto_strong ] )
Run Code Online (Sandbox Code Playgroud)

生成一串伪随机字节,其长度参数确定的字节数.它还指示是否使用加密强算法来生成伪随机字节,并通过可选的crypto_strong参数执行此操作.这种情况很少见,但有些系统可能会损坏或过时.

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

从PHP 7开始,还有random_bytes功能可用

string random_bytes ( int $length )
Run Code Online (Sandbox Code Playgroud)

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

  • 根据https://paragonie.com/blog/2015/07/how-safely-generate-random-strings-and-integers-in-php,这不安全 (4认同)
  • @DavidMeister 字面意思是“快速回答:如果您正在开发 Web 应用程序并且您的项目需要一个简单且安全的解决方案来生成随机整数或字符串,只需使用 random_bytes()” (2认同)

Sco*_*ski 7

PHP附带了一组新的CSPRNG函数(random_bytes()random_int()).将后一个函数转换为字符串生成器函数是微不足道的:

<?php
/**
 * Generate a random string, using a cryptographically secure 
 * pseudorandom number generator (random_int)
 * 
 * For PHP 7, random_int is a PHP core function
 * For PHP 5.x, depends on https://github.com/paragonie/random_compat
 * 
 * @param int $length      How many characters do we want?
 * @param string $keyspace A string of all possible characters
 *                         to select from
 * @return string
 */
function random_str(
    $length,
    $keyspace = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
) {
    $str = '';
    $max = mb_strlen($keyspace, '8bit') - 1;
    if ($max < 1) {
        throw new Exception('$keyspace must be at least two characters long');
    }
    for ($i = 0; $i < $length; ++$i) {
        $str .= $keyspace[random_int(0, $max)];
    }
    return $str;
}
Run Code Online (Sandbox Code Playgroud)

如果您需要在PHP 5项目中使用它,请随意获取random_compat的副本,random_compat是这些函数的polyfill.