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 相关文章推荐
IIS6.0+PHP5.x+MySQL5.x+Zend3.0x+GD+phpMyAdmin2.8x通用安装实例(已经完成)
Dec 06 PHP
PHP 加密解密内部算法
Apr 22 PHP
基于php导出到Excel或CSV的详解(附utf8、gbk 编码转换)
Jun 25 PHP
变量在 PHP7 内部的实现(二)
Dec 21 PHP
php删除数组中重复元素的方法
Dec 22 PHP
CodeIgniter配置之database.php用法实例分析
Jan 20 PHP
浅谈PHP中的面向对象OOP中的魔术方法
Jun 12 PHP
PHP使用XMLWriter读写xml文件操作详解
Jul 31 PHP
Laravel 修改默认日志文件名称和位置的例子
Oct 17 PHP
tp5框架的增删改查操作示例
Oct 31 PHP
基于ThinkPHP删除目录及目录文件函数
Oct 28 PHP
PHP策略模式写法
Apr 01 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
zf框架的registry(注册表)使用示例
2014/03/13 PHP
教你如何在CI框架中使用 .htaccess 隐藏url中index.php
2014/06/09 PHP
PHP里的单例类写法实例
2015/06/25 PHP
php文件类型MIME对照表(比较全)
2016/10/07 PHP
jquery ready函数源代码研究
2009/12/06 Javascript
在多个页面使用同一个HTML片段的代码
2011/03/04 Javascript
js批量设置样式的三种方法不推荐使用with
2013/02/25 Javascript
最精简的JavaScript实现鼠标拖动效果的方法
2015/05/11 Javascript
iscroll碰到Select无法选择下拉刷新的解决办法
2016/05/21 Javascript
轻松搞定js表单验证
2016/10/13 Javascript
JavaScript循环_动力节点Java学院整理
2017/06/28 Javascript
js实现适配移动端的拖动效果
2020/01/13 Javascript
JS函数参数的传递与同名参数实例分析
2020/03/16 Javascript
vue下canvas裁剪图片实例讲解
2020/04/16 Javascript
跟老齐学Python之大话题小函数(1)
2014/10/10 Python
Python编写登陆接口的方法
2017/07/10 Python
Python实现判断一个整数是否为回文数算法示例
2019/03/02 Python
从0开始的Python学习016异常
2019/04/08 Python
Python3.7 新特性之dataclass装饰器
2019/05/27 Python
Django MEDIA的配置及用法详解
2019/07/25 Python
python 使用递归的方式实现语义图片分割功能
2020/07/16 Python
Visual Studio Code搭建django项目的方法步骤
2020/09/17 Python
python+appium+yaml移动端自动化测试框架实现详解
2020/11/24 Python
CSS 3.0文字悬停跳动特效代码
2020/10/26 HTML / CSS
解决CSS3 transition-delay 属性默认值0不带单位失效的问题
2020/10/29 HTML / CSS
澳洲的服装老品牌:SABA
2018/02/06 全球购物
HQhair美国/加拿大:英国化妆品、美容及美发产品商城
2019/04/15 全球购物
免税水晶:Duty Free Crystal
2019/05/13 全球购物
本科生详细的自我评价
2013/09/19 职场文书
《石榴》教学反思
2014/03/02 职场文书
工商行政管理专业求职书
2014/05/23 职场文书
小学生五年级大队长竞选发言稿
2014/09/12 职场文书
党员个人批评与自我批评
2014/10/14 职场文书
幼儿园辞职书
2015/02/26 职场文书
Python socket如何解析HTTP请求内容
2022/02/12 Python
教你如何用cmd快速登录服务器
2022/06/10 Servers