在PHP中安全的随机数生成
使用案例:“我忘记了我的密码”button。 我们无法find用户的原始密码,因为它是以散列forms存储的,所以唯一要做的就是生成一个新的随机密码并通过电子邮件发送给他。 这需要密码不可预知的随机数,对于这个数字,mt_rand不够好,一般来说,我们不能假定托pipe服务将提供访问操作系统来安装密码随机数模块等,所以我正在寻找一种方法在PHP本身中生成安全的随机数字。
我到目前为止提出的解决scheme涉及存储一个初始种子,然后为每个电话,
result = seed seed = sha512(seed . mt_rand())
这是基于sha512哈希函数的安全性(mt_rand调用只是为了让对手获得数据库副本的生命变得更困难)。
我错过了什么,还是有更好的已知解决scheme?
你也可以考虑使用OpenSSL openssl_random_pseudo_bytes,它自PHP 5.3起可用。
string openssl_random_pseudo_bytes ( int $length [, bool &$crypto_strong ] )
生成一串伪随机字节,长度参数决定字节数。 它还指示是否使用密码强的algorithm来生成伪随机字节,并通过可选的crypto_strong参数执行此操作。 这很less会发生,但是有些系统可能会被破坏或者老化。
http://www.php.net/manual/en/function.openssl-random-pseudo-bytes.php
自PHP 7以来,也有random_bytes
函数可用
string random_bytes ( int $length )
我强烈build议将unix系统上的/ dev / urandom或Windows平台上的crypto-api作为密码的熵源。
我不能强调实现哈希的重要性不是不可思议的增加熵的设备。 以这种方式滥用它们并不比在它被散列之前使用seed和rand()数据更安全,我相信你认识到这不是一个好主意。 种子消除(确定性mt_rand()),所以甚至包括它在内也没有任何意义。
人们认为他们聪明聪明,他们的劳动成果是脆弱的系统和设备,使得他们系统的安全性和其他系统的安全性(通过糟糕的build议)处于不必要的危险之中。
两个错误不正确。 一个系统只有最薄弱的一个部分。 这不是许可证或借口让更多的不安全。
这里是一些PHP代码,以获得一个安全的随机128位string,从马克Seecof在php.net此评论 :
“如果你为了安全或者密码的目的需要伪随机比特(egg,随机IV用于分组密码,随机salt用于密码哈希),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的尝试都是安全的,虽然每个都会在对方的平台上静默失败。 把它们留在那里,这样你的代码将更加便携。“
PHP附带一组新的CSPRNG函数( random_bytes()
和random_int()
)。 把后面的函数转换成string生成器函数是很简单的:
<?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; }
如果您需要在PHP 5项目中使用它,请随意获取random_compat的副本,这是一个用于这些函数的polyfill 。