资讯专栏INFORMATION COLUMN

PHP 中的随机数——你觉得可靠么?

Anshiii / 2388人阅读

摘要:本文主要分析以加密为目的的随机数生成问题。一个简例一个好的随机数生成系统能确保生成质量适合的随机数。此处,暂不深入讨论复杂的统计话题,将已知的行为与随机数生成器的结果进行比较,有助于质量评估。

本文主要分析以加密为目的的随机数生成问题。PHP 5 并未提供生成强加密随机数的简便机制,但是,PHP 7 引入了两个 CSPRNG 函数以解决该问题。系 OneAPM 工程师编译整理。

什么是 CSPRNG?

引用维基百科的定义,密码安全的虚拟随机数生成器(Cryptographically Secure Pseudorandom Number Generator,CSPRNG)是带有特定属性使之在密码学中适用的虚拟随机数生成器(pseudo-random number generator,PRNG)。

CSPRNG 主要用于:

生成键(比如:生成复杂的键)

为新的用户账号生成随机密码

加密系统

保证高安全水准的一个重要因素便是高质量的随机数。

PHP 7 中的 CSPRNG

PHP 7 为 CSPRNG 引入了两种新函数:random_bytesrandom_int

random_bytes 函数返回 string 类型,并接受一个 int 类型为参数,该参数规定了所返回字符串的字节长度。

例如:

$bytes = random_bytes("10");
var_dump(bin2hex($bytes));
//possible ouput: string(20) "7dfab0af960d359388e6"  

random_int 函数返回给定范围内的整型数字。

举例:

var_dump(random_int(1, 100));
//possible output: 27
幕后解密

以上函数的随机数来源因环境不同而有所差异:

在 Windows 系统,会使用 CryptGenRandom() 函数。

在其他平台,会优先使用 arc4random_buf() 函数(限 BSD 衍生系统或带 libbsd 的系统)。

若以上两点均不符合,会使用 Linux getrandom(2) 系统调用。

若以上来源均不符合,会抛出 Error

一个简例

一个好的随机数生成系统能确保生成质量适合的随机数。为了检验质量,需要运行一系列的统计试验。此处,暂不深入讨论复杂的统计话题,将已知的行为与随机数生成器的结果进行比较,有助于质量评估。

一个简单的测试方法是掷骰游戏。假设投掷一次,投出6的概率是1/6。如果同时投掷三个骰子,投100次,投得零次、一次、两次及三次6的次数大概是:

0 次6 = 57.9 次

1 次6 = 34.7 次

2 次6 = 6.9 次

3 次6 = 0.5 次

以下是骰子投掷100万次的代码:

$times = 1000000;
$result = [];
for ($i=0; $i<$times; $i++){
    $dieRoll = array(6 => 0); //initializes just the six counting to zero
    $dieRoll[roll()] += 1; //first die
    $dieRoll[roll()] += 1; //second die
    $dieRoll[roll()] += 1; //third die
    $result[$dieRoll[6]] += 1; //counts the sixes
}
function roll(){
    return random_int(1,6);
}
var_dump($result);

用 PHP 7 的 random_int 与简单的 rand 函数测试上面的代码,可能会得到:

Sixes expected random_int rand
0 579000 579430 578179
1 347000 346927 347620
2 69000 68985 69586
3 5000 4658 4615

更直观地查看 randrandom_int 的差别,可以运用方程式放大两组结果的差异,并绘制成图表:

php result - expected result / sqrt(expected)

得到的结果如下:


(结果越接近零越好)

即便三个6的组合表现一般,且该测试与真实应用相比太过简单,我们也能清楚地看到 random_int 的表现优于 rand。况且,随机数生成器的可预见行为、重复行为越少,应用的安全程度就更高。

PHP 5 又如何呢?

默认情况下,PHP 5 并未提供任何强虚拟随机数生成器。而实际使用中,可以使用 openssl_random_pseudo_bytes()mcrypt_create_iv() 方法,或直接结合使用 /dev/random/dev/urandomfread() 方法。此外,还有包 RandomLib 或 libsodium。

如果你想用一个比较好的随机数生成器,同时能与 PHP 7 兼容,你可以使用 Paragon Initiative 公司的 random_compat 库。该库允许在 PHP 5.x 项目中使用 random_bytes()random_int() 方法。

该库可以使用 Composer 进行安装:

composer require paragonie/random_compat
require "vendor/autoload.php";
$string = random_bytes(32);
var_dump(bin2hex($string));
// string(64) "8757a27ce421b3b9363b7825104f8bc8cf27c4c3036573e5f0d4a91ad2aaec6f"
$int = random_int(0,255);
var_dump($int);
// int(81)

random_compat 库使用了与 PHP 7 中不同的优先序列:

如果可用,先使用 fread() /dev/urandom

mcrypt_create_iv($bytes, MCRYPT_CREATE_IV)

COM("CAPICOM.Utilities.1")->GetRandom()

openssl_random_pseudo_bytes()

想了解为何采用这一优先序列,可以阅读本文档。

使用该库生成密码的简单案例如下:

$passwordChar = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
$passwordLength = 8;
$max = strlen($passwordChar) - 1;
$password = "";
for ($i = 0; $i < $passwordLength; ++$i) {
    $password .= $passwordChar[random_int(0, $max)];
}
echo $password;
//possible output: 7rgG8GHu
总结

你应该尽量使用在密码学上安全的虚拟随机数生成器。random_compat 库为此提供了很好的实现方法。

如果你想使用可靠的随机数来源,正如前文所述,尽快开始使用 random_intrandom_bytes 吧!

原文地址:http://www.sitepoint.com/randomness-php-feel-lucky/

OneAPM for PHP 能够深入到所有 PHP 应用内部完成应用性能管理 能够深入到所有 PHP 应用内部完成应用性能管理和监控,包括代码级别性能问题的可见性、性能瓶颈的快速识别与追溯、真实用户体验监控、服务器监控和端到端的应用性能管理。想阅读更多技术文章,请访问 OneAPM 官方技术博客。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/21278.html

相关文章

  • 【译】PHP中的随机性——觉得自己幸运吗?

    摘要:本文分析了生成用于加密的随机数的相关问题。没有提供一种简单的机制来生成密码学上强壮的随机数,但是通过引入几个函数来解决了这个问题。呢缺省情况下,不提供强壮的随机数发生器。如果你想要使用可靠的随机数据源,如你在本文所见,建议尽快使用和 本文分析了生成用于加密的随机数的相关问题。 PHP 5没有提供一种简单的机制来生成密码学上强壮的随机数,但是PHP 7通过引入几个CSPRNG函数来解决了...

    邹强 评论0 收藏0
  • 【译】PHP中的随机性——觉得自己幸运吗?

    摘要:本文分析了生成用于加密的随机数的相关问题。没有提供一种简单的机制来生成密码学上强壮的随机数,但是通过引入几个函数来解决了这个问题。呢缺省情况下,不提供强壮的随机数发生器。如果你想要使用可靠的随机数据源,如你在本文所见,建议尽快使用和 本文分析了生成用于加密的随机数的相关问题。 PHP 5没有提供一种简单的机制来生成密码学上强壮的随机数,但是PHP 7通过引入几个CSPRNG函数来解决了...

    Eric 评论0 收藏0
  • thinkphp整合企业号的坑

    摘要:使用微信企业号回调的坑最近在做企业号回调的接口,之前做过几个企业号的应用了,每次接入到都报各种各样的错误,算哥倒霉,该踩的不该踩的坑全踩了。 ThinkPHP 使用微信企业号回调的坑 最近在做企业号回调的接口,之前做过几个企业号的应用了,每次接入到Thinkphp都报各种各样的错误,算哥倒霉,该踩的不该踩的坑全踩了。 这次掉坑里差点就放弃了,开发过企业号的都知道,企业号回调会经过一个...

    wing324 评论0 收藏0
  • 数据训练营|BAT都在用的方法,详解A/B测试的那些坑!

    摘要:我们再来看国内一线公司内的一个实验吧数据训练营都在用的方法,详解测试的那些坑如上是不同的引导卡片样式的实验,最终结果样式比样式的提升。设指标数值隐变量列显变量列含方案变量。 作者|蚂蚁金服人工智能部产品经理 范磊 本文首发|微信公众号 友盟数据服务 (ID:umengcom),转载请注明出处 If you are not running experiments,you are prob...

    Gilbertat 评论0 收藏0
  • PHP中static与yield关键字的思考

    摘要:先来说说关键字。什么时候用来修饰方法关键字大家都知道是用来修饰方法与属性的。一句话学会面向对象的方式来思考。充分发挥其性能优势,又能解决扩展性差的问题。这里不会进行与的比较。 你以为你知道了一切,只是你以为而已。知识的美妙就在于,一生的时光在它面前显得多么的短暂。 嗯嗯,扯远了,我今天只想说说:static 与 yield。 先来说说 static 关键字。本篇只讲静态方法的使用与后期...

    thursday 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<