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操作excel文件 基于phpexcel
Jul 02 PHP
PHP MySQL应用中使用XOR运算加密算法分享
Aug 28 PHP
PHP __autoload()方法真的影响性能吗?
Mar 30 PHP
php 过滤英文标点符号及过滤中文标点符号代码
Jun 12 PHP
Codeigniter操作数据库表的优化写法总结
Jun 12 PHP
php获取四位字母和数字的随机数的实现方法
Jan 09 PHP
开启PHP Static 关键字之旅模式
Nov 13 PHP
实现WordPress主题侧边栏切换功能的PHP脚本详解
Dec 14 PHP
php计算多个集合的笛卡尔积实例详解
Feb 16 PHP
PHP自动生成缩略图函数的源码示例
Mar 18 PHP
laravel框架 laravel-admin上传图片到oss的方法
Oct 13 PHP
PHP PDO和消息队列的个人理解与应用实例分析
Nov 25 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使用适合阅读的格式显示文件大小的方法
2015/03/05 PHP
Thinkphp 框架扩展之行为扩展原理与实现方法分析
2020/04/23 PHP
Javascript实现的分页函数
2006/12/22 Javascript
JavaScript setTimeout和setInterval的使用方法 说明
2010/03/25 Javascript
js 模拟气泡屏保效果代码
2010/07/10 Javascript
jquery each()源代码
2011/02/14 Javascript
JS仿flash上传头像效果实现代码
2011/07/18 Javascript
获得所有表单值的JQuery实现代码[IE暂不支持]
2012/05/24 Javascript
JavaScript禁止复制与粘贴的实现代码
2016/05/16 Javascript
微信小程序 wxapp地图 map详解
2016/10/31 Javascript
微信小程序 Tab页切换更新数据
2017/01/05 Javascript
JavaScript实现简单音乐播放器
2020/04/17 Javascript
详解Bootstrap 学习(一)入门
2019/04/12 Javascript
Javascript Worker子线程代码实例
2020/02/20 Javascript
js实现双人五子棋小游戏
2020/05/28 Javascript
JavaScript this关键字指向常用情况解析
2020/09/02 Javascript
TensorFlow Session会话控制&amp;Variable变量详解
2018/07/30 Python
python 返回一个列表中第二大的数方法
2019/07/09 Python
pytorch在fintune时将sequential中的层输出方法,以vgg为例
2019/08/20 Python
Python lambda表达式filter、map、reduce函数用法解析
2019/09/11 Python
分享一个pycharm专业版安装的永久使用方法
2019/09/24 Python
Python基于Hypothesis测试库生成测试数据
2020/04/29 Python
pycharm设置默认的UTF-8编码模式的方法详解
2020/06/01 Python
Python 的 __str__ 和 __repr__ 方法对比
2020/09/02 Python
美国折扣宠物药房:Total Pet Supply
2018/05/27 全球购物
前台文员岗位职责及工作流程
2013/11/19 职场文书
大学毕业生通用自我评价
2014/01/05 职场文书
大学生涯自我鉴定
2014/01/16 职场文书
关于孝道的演讲稿
2014/05/21 职场文书
改革共识倡议书
2014/08/29 职场文书
2015年宣传部工作总结范文
2015/03/31 职场文书
关于观后感的作文
2015/06/18 职场文书
MySQL的全局锁和表级锁的具体使用
2021/08/23 MySQL
JavaScript组合继承详解
2021/11/07 Javascript
Windows10安装Apache2.4的方法步骤
2022/06/25 Servers
Python 第三方库 openpyxl 的安装过程
2022/12/24 Python