PHP中的随机性 你觉得自己幸运吗?


Posted in PHP onJanuary 22, 2016

本文分析了生成用于加密的随机数的相关问题。 PHP 5没有提供一种简单的机制来生成密码学上强壮的随机数,但是PHP 7通过引入几个CSPRNG函数来解决了这个问题。

PHP中的随机性 你觉得自己幸运吗?

一、什么是CSPRNG

引用维基百科,一个密码学上安全的伪随机数发生器(Cryptographically Secure Pseudorandom Number Generator 缩写CSPRNG)是一个伪随机数生成器(PRNG),其生成的伪随机数适用于密码学算法。

CSPRNG可能主要用于:

  • 密钥生成(例如,生成复杂的密钥)
  • 为新用户产生随机的密码
  • 加密系统

获得高级别安全性的一个关键方面就是高品质的随机性

二、PHP7 中的CSPRNG

PHP 7引入了两个新函数可以用来实现CSPRNG: random_bytes 和 random_int。

random_bytes 函数返回一个字符串,接受一个int型入参代表返回结果的字节数。

例子:

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

random_int 函数返回一个指定范围内的int型数字。

例子:

var_dump(random_int(1, 100));
//possible output: 27

三、后台运行环境

以上函数的随机性不同的取决于环境:

  • 在window上,CryptGenRandom()总是被使用。
  • 在其他平台,arc4random_buf()如果可用会被使用(在BSD系列或者具有libbsd的系统上成立)
  • 以上都不成立的话,一个linux系统调用getrandom(2)会被使用。
  • 如果还不行,/dev/urandom 会被作为最后一个可使用的工具
  • 如果以上都不行,系统会抛出错误

四、一个简单的测试

一个好的随机数生成系统保证合适的产生“质量”。为了检查这个质量, 通常要执行一连串的统计测试。不需要深入研究复杂的统计主题,比较一个已知的行为和数字生成器的结果可以帮助质量评价。

一个简单的测试是骰子游戏。假设掷1个骰子1次得到结果为6的概率是1/6,那么如果我同时掷3个骰子100次,得到的结果粗略如下:

0 个6 = 57.9 次
1 个6 = 34.7次
2 个6 = 6.9次
3 个6 = 0.5次
以下是是实现实现掷骰子1,000,000次的代码:

$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);

用PHP7 的 random_int 和简单的 rand 函数可能得到如下结果

PHP中的随机性 你觉得自己幸运吗?

如果先看到rand 和 random_int 更好的比较我们可以应用一个公式把结果画在图上。公式是:(php结果-期待的结果)/期待结果的0.5次方。

结果图如下:

PHP中的随机性 你觉得自己幸运吗?

(接近0的值更好)

尽管3个6的结果表现不好,并且这个测试对实际应用来说太过简单我们仍可以看出 random_int 表现优于 rand.

进一步,我们的应用的安全级别由于不可预测性和随机数发生器的可重复行为而得到提升。

PHP5 呢

缺省情况下,PHP5 不提供强壮的随机数发生器。实际上,还是有选择的比如 openssl_random_pseudo_bytes(), mcrypt_create_iv() 或者直接使用fread()函数来使用 /dev/random 或 /dev/urandom 设备。也有一些包比如 RandomLib 或 libsodium.

如果你想要开始使用一个更好的随机数发生器并且同时准备好使用PHP7,你可以使用Paragon Initiative Enterprises random_compat 库。 random_compat 库允许你在 PHP 5.x project.使用 random_bytes() and 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 库和PHP7使用不同的顺序:

fread() /dev/urandom if available
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_int 和 random_bytes。

以上就是关于php随机性的相关内容,希望对大家的学习有所帮助。

PHP 相关文章推荐
Linux下CoreSeek及PHP扩展模块的安装
Sep 23 PHP
web站点获取用户IP的安全方法 HTTP_X_FORWARDED_FOR检验
Jun 01 PHP
php二维数组排序详解
Nov 06 PHP
PHP中对于浮点型的数据需要用不同的方法解决
Mar 11 PHP
浅析application/x-www-form-urlencoded和multipart/form-data的区别
Jun 22 PHP
php生成过去100年下拉列表的方法
Jul 20 PHP
利用Fix Rss Feeds插件修复WordPress的Feed显示错误
Dec 19 PHP
Zend Framework教程之路由功能Zend_Controller_Router详解
Mar 07 PHP
PHP laravel中的多对多关系实例详解
Jun 07 PHP
PHP抽象类与接口的区别详解
Mar 21 PHP
PHP实现的62进制转10进制,10进制转62进制函数示例
Jun 06 PHP
PHP类的自动加载与命名空间用法实例分析
Jun 05 PHP
PHP中的session安全吗?
Jan 22 #PHP
PHP下载远程图片并保存到本地方法总结
Jan 22 #PHP
PHP连接MYSQL数据库实例代码
Jan 20 #PHP
CodeIgniter配置之autoload.php自动加载用法分析
Jan 20 #PHP
Twig模板引擎用法入门教程
Jan 20 #PHP
CodeIgniter控制器之业务逻辑实例分析
Jan 20 #PHP
CodeIgniter自定义控制器MY_Controller用法分析
Jan 20 #PHP
You might like
不重新编译PHP为php增加openssl模块的方法
2011/06/14 PHP
php顺序查找和二分查找示例
2014/03/27 PHP
PHP如何通过AJAX方式实现登录功能
2015/11/23 PHP
PHP实现添加购物车功能
2017/03/06 PHP
js类的静态属性和实例属性的理解
2009/10/01 Javascript
基于jQuery的的一个隔行变色,鼠标移动变色的小插件
2010/07/06 Javascript
JavaScript 类型的包装对象(Typed Wrappers)
2011/10/27 Javascript
JS判断元素为数字的奇异写法分享
2012/08/01 Javascript
关于textarea提交的内容无法换行的解决办法
2013/04/09 Javascript
Jquery在指定DIV加载HTML示例代码
2014/02/17 Javascript
jQuery学习笔记之toArray()
2014/06/09 Javascript
gridview生成时如何去掉style属性中的border-collapse
2014/09/30 Javascript
javascript实现根据3原色制作颜色选择器的方法
2015/07/17 Javascript
js 自带的 map() 方法全面了解
2016/08/16 Javascript
Angularjs之filter过滤器(推荐)
2016/11/27 Javascript
js实现1,2,3,5数字按照概率生成
2017/09/12 Javascript
在nginx上部署vue项目(history模式)的方法
2017/12/28 Javascript
vue项目中引入noVNC远程桌面的方法
2018/03/05 Javascript
详解VUE自定义组件中用.sync修饰符与v-model的区别
2018/06/26 Javascript
[17:13]DOTA2 HEROS教学视频教你分分钟做大人-斯拉克
2014/06/13 DOTA
Python实现Linux中的du命令
2017/06/12 Python
python利用lxml读写xml格式的文件
2017/08/10 Python
Python线程创建和终止实例代码
2018/01/20 Python
python实现手机通讯录搜索功能
2018/02/22 Python
Pyqt5 实现跳转界面并关闭当前界面的方法
2019/06/19 Python
Python如何计算语句执行时间
2019/11/22 Python
python利用os模块编写文件复制功能——copy()函数用法
2020/07/13 Python
乌克兰移动电子产品和相关配件的在线商店:iTMag
2020/03/16 全球购物
项目经理任命书
2014/06/04 职场文书
户籍证明模板
2014/09/28 职场文书
大学感恩节活动总结
2015/05/05 职场文书
教学质量月活动总结
2015/05/11 职场文书
老舍《猫》教学反思
2016/02/17 职场文书
八年级语文教学反思
2016/03/03 职场文书
2019年暑期法院实习报告
2019/12/18 职场文书
css之clearfix的用法深入理解(必看篇)
2023/05/21 HTML / CSS