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 fread()使用技巧
Jan 22 PHP
Windows下安装Memcached的步骤说明
Apr 25 PHP
php读取excel文件示例分享(更新修改excel)
Feb 27 PHP
Thinkphp关闭缓存的方法
Jun 26 PHP
PHP实现的一致性哈希算法完整实例
Nov 14 PHP
详解php魔术方法(Magic methods)的使用方法
Feb 14 PHP
Linux php 中文乱码的快速解决方法
May 13 PHP
使用php完成常见的文件上传功能(推荐)
Jan 13 PHP
阿里云PHP SMS短信服务验证码发送方法
Jul 11 PHP
PHP批量删除jQuery操作
Jul 23 PHP
PHP+AJAX 投票器功能
Nov 11 PHP
php 使用ActiveMQ发送消息,与处理消息操作示例
Feb 23 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 Class&amp;Object -- PHP 自排序二叉树的深入解析
2013/06/25 PHP
php curl获取网页内容(IPV6下超时)的解决办法
2013/07/16 PHP
typecho插件编写教程(三):保存配置
2015/05/28 PHP
PHP模板引擎Smarty内置变量调解器用法详解
2016/04/11 PHP
laravel 解决Validator使用中出现的问题
2019/10/25 PHP
网站上面有这种切换效果
2006/06/26 Javascript
JavaScript中访问节点对象的方法有哪些如何使用
2013/09/24 Javascript
使用RequireJS库加载JavaScript模块的实例教程
2016/06/06 Javascript
JS实现兼容各种浏览器的高级拖动方法完整实例【测试可用】
2016/06/21 Javascript
如何提高Dom访问速度
2017/01/05 Javascript
利用CSS、JavaScript及Ajax实现图片预加载的三大方法
2017/01/22 Javascript
详解wow.js中各种特效对应的类名
2017/09/13 Javascript
解决vue 引入子组件报错的问题
2018/09/06 Javascript
jQuery AJAX与jQuery事件的分析讲解
2019/02/18 jQuery
Vue多组件仓库开发与发布详解
2019/02/28 Javascript
layui 弹出删除确认界面的实例
2019/09/06 Javascript
Vue 禁用浏览器的前进后退操作
2020/09/04 Javascript
基于vue+echarts数据可视化大屏展示的实现
2020/12/25 Vue.js
python批量导出导入MySQL用户的方法
2013/11/15 Python
跟老齐学Python之有容乃大的list(4)
2014/09/28 Python
Python正则表达式匹配ip地址实例
2014/10/09 Python
Python基于有道实现英汉字典功能
2015/07/25 Python
Python中django学习心得
2017/12/06 Python
用Python写王者荣耀刷金币脚本
2017/12/21 Python
pip安装时ReadTimeoutError的解决方法
2018/06/12 Python
pygame实现雷电游戏雏形开发
2018/11/20 Python
对DataFrame数据中的重复行,利用groupby累加合并的方法详解
2019/01/30 Python
python搜索包的路径的实现方法
2019/07/19 Python
Python使用pymysql模块操作mysql增删改查实例分析
2019/12/19 Python
python脚本监控logstash进程并邮件告警实例
2020/04/28 Python
美国户外运动商店:Sun & Ski
2018/08/23 全球购物
FC-Moto瑞典:欧洲最大的摩托车服装和头盔商店之一
2018/11/27 全球购物
俄语专业毕业生推荐信
2013/10/28 职场文书
2013的个人自我评价
2013/12/26 职场文书
创业培训计划书
2014/05/03 职场文书
2014年廉洁自律承诺书
2014/05/26 职场文书