本文主要分析以加密爲目的的隨機數生成問題。PHP 5 並未提供生成強加密隨機數的簡便機制,可是,PHP 7 引入了兩個 CSPRNG 函數以解決該問題。系 OneAPM 工程師編譯整理。php
引用維基百科的定義,密碼安全的虛擬隨機數生成器(Cryptographically Secure Pseudorandom Number Generator,CSPRNG)是帶有特定屬性使之在密碼學中適用的虛擬隨機數生成器(pseudo-random number generator,PRNG)。html
CSPRNG 主要用於:linux
保證高安全水準的一個重要因素即是高質量的隨機數。git
PHP 7 爲 CSPRNG 引入了兩種新函數:random_bytes
與 random_int
。github
random_bytes
函數返回 string
類型,並接受一個 int
類型爲參數,該參數規定了所返回字符串的字節長度。安全
例如:服務器
$bytes = random_bytes('10'); var_dump(bin2hex($bytes)); //possible ouput: string(20) "7dfab0af960d359388e6"
random_int
函數返回給定範圍內的整型數字。composer
舉例:dom
var_dump(random_int(1, 100)); //possible output: 27
以上函數的隨機數來源因環境不一樣而有所差別:函數
CryptGenRandom()
函數。arc4random_buf()
函數(限 BSD 衍生系統或帶 libbsd 的系統)。Error
。一個好的隨機數生成系統能確保生成質量適合的隨機數。爲了檢驗質量,須要運行一系列的統計試驗。此處,暫不深刻討論複雜的統計話題,將已知的行爲與隨機數生成器的結果進行比較,有助於質量評估。
一個簡單的測試方法是擲骰遊戲。假設投擲一次,投出6的機率是1/6。若是同時投擲三個骰子,投100次,投得零次、一次、兩次及三次6的次數大概是:
如下是骰子投擲100萬次的代碼:
$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);
用 PHP 7 的 random_int
與簡單的 rand
函數測試上面的代碼,可能會獲得:
<table> <thead> <tr> <th>Sixes</th> <th>expected</th> <th>random_int</th> <th>rand</th> </tr> </thead> <tbody><tr> <td>0</td> <td>579000</td> <td>579430</td> <td>578179</td> </tr> <tr> <td>1</td> <td>347000</td> <td>346927</td> <td>347620</td> </tr> <tr> <td>2</td> <td>69000</td> <td>68985</td> <td>69586</td> </tr> <tr> <td>3</td> <td>5000</td> <td>4658</td> <td>4615</td> </tr> </tbody></table>
更直觀地查看 rand
與 random_int
的差異,能夠運用方程式放大兩組結果的差別,並繪製成圖表:
php result - expected result / sqrt(expected)
獲得的結果以下:
(結果越接近零越好)
即使三個6的組合表現通常,且該測試與真實應用相比太過簡單,咱們也能清楚地看到 random_int
的表現優於 rand
。何況,隨機數生成器的可預見行爲、重複行爲越少,應用的安全程度就更高。
默認狀況下,PHP 5 並未提供任何強虛擬隨機數生成器。而實際使用中,能夠使用 openssl_random_pseudo_bytes()
、mcrypt_create_iv()
方法,或直接結合使用 /dev/random
或 /dev/urandom
與 fread()
方法。此外,還有包 RandomLib 或 libsodium。
若是你想用一個比較好的隨機數生成器,同時能與 PHP 7 兼容,你能夠使用 Paragon Initiative 公司的 random_compat
庫。該庫容許在 PHP 5.x 項目中使用 random_bytes()
與 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
庫使用了與 PHP 7 中不一樣的優先序列:
想了解爲什麼採用這一優先序列,能夠閱讀本文檔。
使用該庫生成密碼的簡單案例以下:
$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
吧!
原文地址:http://www.sitepoint.com/randomness-php-feel-lucky/
OneAPM for PHP 可以深刻到全部 PHP 應用內部完成應用性能管理 可以深刻到全部 PHP 應用內部完成應用性能管理和監控,包括代碼級別性能問題的可見性、性能瓶頸的快速識別與追溯、真實用戶體驗監控、服務器監控和端到端的應用性能管理。想閱讀更多技術文章,請訪問 OneAPM 官方技術博客。