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 相关文章推荐
PHP 和 HTML
Oct 09 PHP
动易数据转成dedecms的php程序
Apr 07 PHP
PHP 批量删除数据的方法分析
Oct 30 PHP
PHP5 的对象赋值机制介绍
Aug 02 PHP
PHP中读写文件实现代码
Oct 20 PHP
自己在做项目过程中学到的PHP知识收集
Aug 20 PHP
简单的php数据库操作类代码(增,删,改,查)
Apr 08 PHP
php实现图形显示Ip地址的代码及注释
Jan 20 PHP
ThinkPHP连接Oracle数据库
Apr 22 PHP
PHP魔术方法以及关于独立实例与相连实例的全面讲解
Oct 18 PHP
Laravel 5.5官方推荐的Nginx配置学习教程
Oct 06 PHP
PHP实现转盘抽奖算法分享
Apr 15 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 404错误页面实现代码
2009/06/22 PHP
ThinkPHP框架设计及扩展详解
2014/11/25 PHP
thinkphp中空模板与空模块的用法实例
2014/11/26 PHP
PHP-FPM之Chroot执行环境详解
2015/08/03 PHP
PHP5.2中PDO的简单使用方法
2016/03/25 PHP
使用jquery实现图文切换效果另加特效
2013/01/20 Javascript
table insertRow、deleteRow定义和用法总结
2014/05/14 Javascript
scrollWidth,clientWidth,offsetWidth的区别
2015/01/13 Javascript
基于jQuery实现自动轮播旋转木马特效
2015/11/02 Javascript
jQuery图片轮播插件——前端开发必看
2016/05/31 Javascript
图文详解JavaScript的原型对象及原型链
2016/08/02 Javascript
AngularJS实现星星等级评分功能
2016/09/24 Javascript
Bootstrap popover用法详解
2016/12/22 Javascript
NodeJS实现微信公众号关注后自动回复功能
2017/05/31 NodeJs
nodejs 搭建简易服务器的图文教程(推荐)
2017/07/18 NodeJs
javascript  删除select中的所有option的实例
2017/09/17 Javascript
Vuejs 2.0 子组件访问/调用父组件的方法(示例代码)
2018/02/08 Javascript
JS实现图片轮播效果实例详解【可自动和手动】
2019/04/04 Javascript
微信小程序实现单个卡片左滑显示按钮并防止上下滑动干扰功能
2019/12/06 Javascript
[01:38:19]夜魇凡尔赛茶话会 第五期
2021/03/11 DOTA
跟老齐学Python之玩转字符串(3)
2014/09/14 Python
python获取当前时间对应unix时间戳的方法
2015/05/15 Python
Python中的Numpy矩阵操作
2018/08/12 Python
python 递归深度优先搜索与广度优先搜索算法模拟实现
2018/10/22 Python
Python语法分析之字符串格式化
2019/06/13 Python
python 基于PYMYSQL使用MYSQL数据库
2020/12/24 Python
selenium如何定位span元素的实现
2021/01/13 Python
在印度上传处方,在线订购药品:Medlife
2019/03/28 全球购物
Linux如何压缩可执行文件
2013/10/21 面试题
实习心得体会
2014/01/02 职场文书
大学生入党思想汇报
2014/01/14 职场文书
合作协议书模板2014
2014/09/26 职场文书
2014年车间工作总结
2014/11/21 职场文书
2015年小学教科研工作总结
2015/07/20 职场文书
2016学习医德医风心得体会
2016/01/25 职场文书
Nginx报错104:Connection reset by peer问题的解决及分析
2022/07/23 Servers