В этой статье анализируются проблемы, связанные с генерацией случайных чисел, используемых в целях криптографии. PHP 5 не предоставляет простой механизм для генерации криптографически сильных случайных чисел, в то время как PHP 7 решает эту проблему, вводя несколько функций CSPRNG .
Что такое CSPRNG?
Цитируя Википедию , криптографически безопасный генератор псевдослучайных чисел (CSPRNG) — это генератор псевдослучайных чисел (PRNG) со свойствами, которые делают его пригодным для использования в криптографии.
CSPRNG может быть в основном полезен для:
- Генерация ключей (например, генерация сложных ключей)
- Создание случайных паролей для новых учетных записей пользователей
- Системы шифрования
Центральным аспектом поддержания высокого уровня безопасности является высокое качество случайности.
CSPRNG в PHP 7
В PHP 7 представлены две новые функции, которые можно использовать для CSPRNG: random_bytes
и random_int
.
Функция random_bytes
возвращает string
и принимает в качестве входных данных int
представляющий длину в байтах, которая должна быть возвращена.
Пример:
$bytes = random_bytes ( '10' ); var_dump ( bin2hex ( $bytes ));
//possible ouput: string(20) "7dfab0af960d359388e6"
Функция random_int
возвращает целое число в заданном диапазоне.
Пример:
var_dump ( random_int ( 1 , 100 ));
//possible output: 27
За кулисами
Источники случайности указанных функций различны в зависимости от среды:
- В Windows всегда будет использоваться
CryptGenRandom()
. - На других платформах будет использоваться
arc4random_buf()
, если она доступна (верно для производных BSD или систем с libbsd). - В противном случае будет использоваться системный вызов getrandom (2) в Linux.
- Если все остальное терпит неудачу / Dev / Urandom будет использоваться в качестве окончательного отступления.
- Если ни один из вышеперечисленных источников недоступен,
Error
.
Простой тест
Хорошая система генерации случайных чисел обеспечивает правильное «качество» поколений. Чтобы проверить это качество, часто выполняется ряд статистических тестов. Не углубляясь в сложные статистические темы, сравнение известного поведения с результатом генератора чисел может помочь в оценке качества.
Один простой тест — игра в кости. Предполагая, что шансы бросить шестерку с одним кубиком равны один к шести, если я брошу три кубика одновременно 100 раз, ожидаемые значения для шестерок 0, 1, 2 и 3 примерно равны:
- 0 шестерок = 57,9 раз
- 1 шестерка = 34,7 раза
- 2 шестерки = 6,9 раза
- 3 шестерки = 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
может привести к:
шестерки | ожидаемый | random_int |
rand |
---|---|---|---|
0 | 579000 | 579430 | 578179 |
1 | 347000 | 346927 | 347620 |
2 | 69000 | 68985 | 69586 |
3 | 5000 | 4658 | 4615 |
Чтобы увидеть лучшее сравнение между rand
и random_int
мы можем random_int
результаты на графике, применив формулу для увеличения различий между значениями: php result - expected result / sqrt(expected)
.
Полученный график будет:
(значения, близкие к нулю, лучше)
Даже если комбинация «три шестерки» не работает random_int
, а тест слишком прост для реального приложения, мы ясно видим, что random_int
работает лучше, чем rand
.
Кроме того, безопасность приложения повышается за счет отсутствия предсказуемого, повторяемого поведения в принятом генераторе случайных чисел.
Как насчет PHP 5?
По умолчанию PHP 5 не предоставляет сильных генераторов псевдослучайных чисел. В действительности, есть несколько опций, таких как openssl_random_pseudo_bytes()
, mcrypt_create_iv()
или прямое использование устройств /dev/random
или /dev/urandom
с fread()
. Есть также пакеты, такие как RandomLib или libsodium .
Если вы хотите начать использовать хороший генератор случайных чисел и в то же время быть готовым к PHP 7, вы можете использовать библиотеку Paragon Initiative Enterprises random_compat
. Библиотека random_compat
позволяет использовать random_bytes()
и random_int()
в вашем проекте PHP 5.x.
Библиотека может быть установлена через 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:
-
fread()
/dev/urandom
если доступно -
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
.
Вопросы или комментарии? Оставь их ниже!
Дальнейшее чтение
Описание | Ссылка на сайт |
---|---|
Die Hard Test | https://en.wikipedia.org/wiki/Diehard_tests |
Тест хи-квадрат с примером игры в кости | http://bit.ly/1Mrptf5 |
Тест Колмогорова-Смирнова | https://en.wikipedia.org/wiki/Kolmogorov-Smirnov_test |
Спектральный тест | http://random.mat.sbg.ac.at/tests/theory/spectral/ |
Набор тестов RaBiGeTe | http://cristianopi.altervista.org/RaBiGeTe_MT |
Генерация случайных чисел в PHP (2011) | http://blog.ircmaxell.com/2011/07/random-number-generation-in-php.html |
Тестирование RNG часть 1 и 2 | http://ubm.io/1Ot46vL http://ubm.io/1VNzh3N |
Подтверждения
Большое спасибо следующим рецензентам за помощь в этой статье!