ホームページ >バックエンド開発 >PHPチュートリアル >PHP のランダム性 - あなたは幸運だと思いますか?
この記事では、暗号化のための乱数の生成に関連する問題を分析します。 PHP 5 には、暗号的に強力な乱数を生成する単純なメカニズムが提供されていませんでしたが、PHP 7 では、いくつかの CSPRNG 関数を導入することでこの問題を解決しました。
Wikipedia より引用、暗号的に安全な擬似乱数生成器 (Cryptographically Secure Pseudorandom Number Generator 略称 CSPRNG) は、擬似乱数生成器 (PRNG) です。 )、暗号化アルゴリズムに適した擬似乱数を生成します。
鍵生成 (例: 複雑な鍵の生成)
新しいユーザー用生成されたランダムなパスワード
暗号化システム
高レベルのセキュリティを達成するための重要な側面は、高品質のランダム性です
PHP 7 では、CSPRNG の実装に使用できる 2 つの新しい関数、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
Windows では、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 6s = 6.9 倍
3 6s = 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 の randan_int を使用して簡単に実行できます。 rand関数 以下の結果が得られます
| expected | ランダム_int | |||||||||||||||
0 | 579000 | 579430 | |||||||||||||||
1 | 347000 | 346927 | td>|||||||||||||||
2 | 69000 | 68985 | |||||||||||||||
3 | 5000 | 4658 |
如果先看到rand 和 random_int 更好的比较我们可以应用一个公式把结果画在图上。公式是:(php结果-期待的结果)/期待结果的0.5次方。
(接近0的值更好)
尽管3个6的结果表现不好,并且这个测试对实际应用来说太过简单我们仍可以看出 random_int 表现优于 rand.
进一步,我们的应用的安全级别由于不可预测性和随机数发生器的可重复行为而得到提升。
缺省情况下,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)
fread() /dev/urandom if available mcrypt_create_iv($bytes, MCRYPT_CREATE_IV) COM('CAPICOM.Utilities.1')->GetRandom() openssl_random_pseudo_bytes()
想知道为什么是这个顺序建议阅读 documentation .
$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.codeceo.com/article/php-random.html
英文原文: Randomness in PHP – Do You Feel Lucky?