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 相关文章推荐
mysql 字段类型说明
Apr 27 PHP
PHP __autoload()方法真的影响性能吗?
Mar 30 PHP
php单例模式实现(对象只被创建一次)
Dec 05 PHP
php多文件上传功能实现原理及代码
Apr 18 PHP
使用php 获取时间今天明天昨天时间戳的详解
Jun 20 PHP
PHP处理大量表单字段的便捷方法
Feb 07 PHP
php实现粘贴截图并完成上传功能
May 17 PHP
php实现只保留mysql中最新1000条记录
Jun 18 PHP
PHP实现文件上传与下载实例与总结
Mar 13 PHP
PHP生成各种随机验证码的方法总结【附demo源码】
Jun 05 PHP
php实现的pdo公共类定义与用法示例
Jul 19 PHP
PHP根据key删除数组中指定的元素
Feb 28 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
深入HTTP响应状态码速查表的详解
2013/06/07 PHP
PHP微信开发之根据用户回复关键词\位置返回附近信息
2016/06/24 PHP
Ajax和PHP正则表达式验证表单及验证码
2016/09/24 PHP
语义化 H1 标签
2008/01/14 Javascript
基于JQuery的数字改变的动画效果--可用来做计数器
2010/08/11 Javascript
JavaScript开发规范要求(规范化代码)
2010/08/16 Javascript
利用进制转换压缩数字函数分享
2014/01/02 Javascript
javascript实现多级联动下拉菜单的方法
2015/02/06 Javascript
jQuery Ajax中的事件详细介绍
2015/04/16 Javascript
AngularJS学习笔记之ng-options指令
2015/06/16 Javascript
js实现楼层效果的简单实例
2016/07/15 Javascript
Vue.js组件tab实现选项卡切换
2020/03/23 Javascript
Node.js  事件循环详解及实例
2017/08/06 Javascript
JS非空验证及邮箱验证的实例
2017/08/11 Javascript
浅谈react 同构之样式直出
2017/11/07 Javascript
详解Vue项目部署遇到的问题及解决方案
2019/01/11 Javascript
微信小程序中转义字符的处理方法
2019/03/28 Javascript
vue请求本地自己编写的json文件的方法
2019/04/25 Javascript
js函数和this用法实例分析
2020/03/13 Javascript
python网络编程学习笔记(四):域名系统
2014/06/09 Python
python新手经常遇到的17个错误分析
2014/07/30 Python
PHP魔术方法__ISSET、__UNSET使用实例
2014/11/25 Python
在Python编程过程中用单元测试法调试代码的介绍
2015/04/02 Python
一步步教你用Python实现2048小游戏
2017/01/19 Python
正确理解python中的关键字“with”与上下文管理器
2017/04/21 Python
对Python模块导入时全局变量__all__的作用详解
2019/01/11 Python
为什么是 Python -m
2020/06/19 Python
css3实现画半圆弧线的示例代码
2017/11/06 HTML / CSS
检测浏览器是否支持html5视频的代码
2013/03/28 HTML / CSS
世界第一冲浪品牌:O’Neill
2016/08/30 全球购物
2016年国培心得体会及反思
2016/01/13 职场文书
2019年幼儿园家长接送责任书
2019/10/29 职场文书
如何利用python和DOS获取wifi密码
2021/03/31 Python
详解TS数字分隔符和更严格的类属性检查
2021/05/06 Javascript
解决Python中的modf()函数取小数部分不准确问题
2021/05/28 Python
nginx实现动静分离的方法示例
2021/11/07 Servers