PHP中的隨機(jī)性 你覺(jué)得自己幸運(yùn)嗎?
本文分析了生成用于加密的隨機(jī)數(shù)的相關(guān)問(wèn)題。 PHP 5沒(méi)有提供一種簡(jiǎn)單的機(jī)制來(lái)生成密碼學(xué)上強(qiáng)壯的隨機(jī)數(shù),但是PHP 7通過(guò)引入幾個(gè)CSPRNG函數(shù)來(lái)解決了這個(gè)問(wèn)題。

一、什么是CSPRNG
引用維基百科,一個(gè)密碼學(xué)上安全的偽隨機(jī)數(shù)發(fā)生器(Cryptographically Secure Pseudorandom Number Generator 縮寫(xiě)CSPRNG)是一個(gè)偽隨機(jī)數(shù)生成器(PRNG),其生成的偽隨機(jī)數(shù)適用于密碼學(xué)算法。
CSPRNG可能主要用于:
- 密鑰生成(例如,生成復(fù)雜的密鑰)
- 為新用戶產(chǎn)生隨機(jī)的密碼
- 加密系統(tǒng)
獲得高級(jí)別安全性的一個(gè)關(guān)鍵方面就是高品質(zhì)的隨機(jī)性
二、PHP7 中的CSPRNG
PHP 7引入了兩個(gè)新函數(shù)可以用來(lái)實(shí)現(xiàn)CSPRNG: random_bytes 和 random_int。
random_bytes 函數(shù)返回一個(gè)字符串,接受一個(gè)int型入?yún)⒋矸祷亟Y(jié)果的字節(jié)數(shù)。
例子:
$bytes = random_bytes('10');
var_dump(bin2hex($bytes));
//possible ouput: string(20) "7dfab0af960d359388e6"
random_int 函數(shù)返回一個(gè)指定范圍內(nèi)的int型數(shù)字。
例子:
var_dump(random_int(1, 100)); //possible output: 27
三、后臺(tái)運(yùn)行環(huán)境
以上函數(shù)的隨機(jī)性不同的取決于環(huán)境:
- 在window上,CryptGenRandom()總是被使用。
- 在其他平臺(tái),arc4random_buf()如果可用會(huì)被使用(在BSD系列或者具有l(wèi)ibbsd的系統(tǒng)上成立)
- 以上都不成立的話,一個(gè)linux系統(tǒng)調(diào)用getrandom(2)會(huì)被使用。
- 如果還不行,/dev/urandom 會(huì)被作為最后一個(gè)可使用的工具
- 如果以上都不行,系統(tǒng)會(huì)拋出錯(cuò)誤
四、一個(gè)簡(jiǎn)單的測(cè)試
一個(gè)好的隨機(jī)數(shù)生成系統(tǒng)保證合適的產(chǎn)生“質(zhì)量”。為了檢查這個(gè)質(zhì)量, 通常要執(zhí)行一連串的統(tǒng)計(jì)測(cè)試。不需要深入研究復(fù)雜的統(tǒng)計(jì)主題,比較一個(gè)已知的行為和數(shù)字生成器的結(jié)果可以幫助質(zhì)量評(píng)價(jià)。
一個(gè)簡(jiǎn)單的測(cè)試是骰子游戲。假設(shè)擲1個(gè)骰子1次得到結(jié)果為6的概率是1/6,那么如果我同時(shí)擲3個(gè)骰子100次,得到的結(jié)果粗略如下:
0 個(gè)6 = 57.9 次
1 個(gè)6 = 34.7次
2 個(gè)6 = 6.9次
3 個(gè)6 = 0.5次
以下是是實(shí)現(xiàn)實(shí)現(xiàn)擲骰子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 和簡(jiǎn)單的 rand 函數(shù)可能得到如下結(jié)果

如果先看到rand 和 random_int 更好的比較我們可以應(yīng)用一個(gè)公式把結(jié)果畫(huà)在圖上。公式是:(php結(jié)果-期待的結(jié)果)/期待結(jié)果的0.5次方。
結(jié)果圖如下:

(接近0的值更好)
盡管3個(gè)6的結(jié)果表現(xiàn)不好,并且這個(gè)測(cè)試對(duì)實(shí)際應(yīng)用來(lái)說(shuō)太過(guò)簡(jiǎn)單我們?nèi)钥梢钥闯?random_int 表現(xiàn)優(yōu)于 rand.
進(jìn)一步,我們的應(yīng)用的安全級(jí)別由于不可預(yù)測(cè)性和隨機(jī)數(shù)發(fā)生器的可重復(fù)行為而得到提升。
PHP5 呢
缺省情況下,PHP5 不提供強(qiáng)壯的隨機(jī)數(shù)發(fā)生器。實(shí)際上,還是有選擇的比如 openssl_random_pseudo_bytes(), mcrypt_create_iv() 或者直接使用fread()函數(shù)來(lái)使用 /dev/random 或 /dev/urandom 設(shè)備。也有一些包比如 RandomLib 或 libsodium.
如果你想要開(kāi)始使用一個(gè)更好的隨機(jī)數(shù)發(fā)生器并且同時(shí)準(zhǔn)備好使用PHP7,你可以使用Paragon Initiative Enterprises random_compat 庫(kù)。 random_compat 庫(kù)允許你在 PHP 5.x project.使用 random_bytes() and random_int()
這個(gè)庫(kù)可以通過(guò)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 庫(kù)和PHP7使用不同的順序:
fread() /dev/urandom if available
mcrypt_create_iv($bytes, MCRYPT_CREATE_IV)
COM('CAPICOM.Utilities.1')->GetRandom()
openssl_random_pseudo_bytes()
這個(gè)庫(kù)的一個(gè)簡(jiǎn)單應(yīng)用用來(lái)產(chǎn)生密碼:
$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
總結(jié)
你總是應(yīng)該使用一個(gè)密碼學(xué)上安全的偽隨機(jī)數(shù)生成器,random_compat 庫(kù)提供了一種好的實(shí)現(xiàn)。
如果你想要使用可靠的隨機(jī)數(shù)據(jù)源,如你在本文所見(jiàn),建議盡快使用 random_int 和 random_bytes。
以上就是關(guān)于php隨機(jī)性的相關(guān)內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助。
- php生成隨機(jī)數(shù)或者字符串的代碼
- PHP n個(gè)不重復(fù)的隨機(jī)數(shù)生成代碼
- PHP 動(dòng)態(tài)隨機(jī)生成驗(yàn)證碼類代碼
- 超級(jí)好用的一個(gè)php上傳圖片類(隨機(jī)名,縮略圖,加水印)
- php數(shù)組函數(shù)序列 之shuffle()和array_rand() 隨機(jī)函數(shù)使用介紹
- 適用于抽獎(jiǎng)程序、隨機(jī)廣告的PHP概率算法實(shí)例
- php使用array_rand()函數(shù)從數(shù)組中隨機(jī)選擇一個(gè)或多個(gè)元素
- php生成隨機(jī)數(shù)的三種方法
- PHP生成不重復(fù)隨機(jī)數(shù)的方法匯總
- php隨機(jī)生成數(shù)字字母組合的方法
相關(guān)文章
php存儲(chǔ)過(guò)程調(diào)用實(shí)例代碼
php存儲(chǔ)過(guò)程調(diào)用舉例,供大家學(xué)習(xí)參考2013-02-02
詳解php魔術(shù)方法(Magic methods)的使用方法
有些東西如果不是經(jīng)常使用,很容易忘記,比如魔術(shù)方法和魔術(shù)常量,這篇文章主要介紹了php魔術(shù)方法(Magic methods)的使用方法,感興趣的小伙伴們可以參考一下2016-02-02
php中unable to fork報(bào)錯(cuò)簡(jiǎn)單解決方法
在本篇內(nèi)容里小編給大家整理的是一篇關(guān)于php中unable to fork報(bào)錯(cuò)簡(jiǎn)單解決方法,對(duì)此有興趣的朋友們可以跟著學(xué)習(xí)下。2021-02-02
php實(shí)現(xiàn)的CSS更新類實(shí)例
這篇文章主要介紹了php實(shí)現(xiàn)的CSS更新類及其用法實(shí)例,包括了針對(duì)模板文件的檢查、更新與替換模板文件等功能,非常實(shí)用,需要的朋友可以參考下2014-09-09
php生成短網(wǎng)址/短鏈接原理和用法實(shí)例分析
這篇文章主要介紹了php生成短網(wǎng)址/短鏈接原理和用法,結(jié)合實(shí)例形式分析了php生成短網(wǎng)址/短鏈接的基本原理、實(shí)現(xiàn)方法與相關(guān)注意事項(xiàng),需要的朋友可以參考下2020-05-05
php中使用preg_replace函數(shù)匹配圖片并加上鏈接的方法
preg_replace 執(zhí)行正則表達(dá)式的搜索和替換,如果只是單純的匹配字符串建議使用str_replace(),因?yàn)槠鋱?zhí)行效率高的多2013-02-02

