security — генерировать безопасное случайное целое число в диапазоне с PHP 5.6

Я хотел бы создать безопасное случайное число между $min а также $max в PHP5.6. И то и другое rand() а также mt_rand() в PHP считаются не криптографически безопасными.

От документы:

предосторожность

Эта функция не генерирует криптографически безопасные значения и не должна использоваться в криптографических целях. Если вам нужно криптографически безопасное значение, рассмотрите возможность использования взамен random_int (), random_bytes () или openssl_random_pseudo_bytes ().

PHP 7 добавляет random_int() (документы), которая идеально подходит для моего варианта использования:

random_int — генерирует криптографически безопасные псевдослучайные числа

Но как эта функциональность может быть достигнута в PHP 5.6?

Моя наивная попытка была такая:

<?php
function secure_rand($min, $max)
{
return (unpack("N", openssl_random_pseudo_bytes(4)) % ($max - $min)) + $min;
}

Но я, кажется, всегда получаю «2» при звонке secure_rand(1, 100), Я также читал, что использование операции модуля таким образом может создать смещение. Как я могу подражать random_int() в PHP 5.6?

1

Решение

Могу ли я познакомить вас с random_compat, какие полифилы random_bytes() а также random_int() в проектах PHP 5? (Sidenote: среди других проектов, он был подхвачен WordPress в 4.4.)

function secure_rand($min, $max)
{
return (unpack("N", openssl_random_pseudo_bytes(4)) % ($max - $min)) + $min;
}

Даже если бы это делало то, что вы хотели, это смещенный генератор случайных чисел когда ($max - $min) не является четной степенью 2.

3

Другие решения

Нашел довольно хорошо работающее решение. В примере используется расширение mcrypt, но оно также работает с openssl_random_pseudo_bytes() если вам нужно больше информации, посмотрите Вот.

function secure_rand( $min, $max ) {
$diff = $max - $min;
if ($diff < 0 || $diff > 0x7FFFFFFF) {
throw new RuntimeException("Bad range");
}
$bytes = mcrypt_create_iv( 4, MCRYPT_DEV_URANDOM );

// if mcrypt is not enabled on your server, you can use this
//$bytes = openssl_random_pseudo_bytes( 4 );

// if mbstring is not enabled, you can also use iconv_strlen
if ($bytes === false || mb_strlen($bytes, '8bit') != 4) {
throw new RuntimeException("Unable to get 4 bytes");
}

$ary = unpack("Nint", $bytes);
$val = $ary['int'] & 0x7FFFFFFF;   // 32-bit safe
$fp = $val / 2147483647.0; // convert to [0,1]
// if you really need a type of int take this
// return (int) round($fp * $diff) + $min;
// otherwise it will return a float without decimal numbers
return round($fp * $diff) + $min;
}

var_dump( secure_rand( 1, 1000 ) );
var_dump( secure_rand( 1, 20 ) );
var_dump( secure_rand( 1, 10 ) );
var_dump( secure_rand( 1, 5000 ) );
var_dump( secure_rand( 1, 1111111 ) );

Обновлено: комментарии в источнике, удалено приведение к float / int, используется mb_strlen() вместо strlen()

2

Ты можешь использовать openssl_random_pseudo_bytes, как это доступно с PHP 5.3

Генерирует строку псевдослучайных байтов с числом байтов, определяемым параметром длины.

Он также указывает, использовался ли криптографически стойкий алгоритм для создания псевдослучайных байтов, и делает это с помощью необязательного параметра crypto_strong. Это редко для ЛОЖЬ, но некоторые системы могут быть сломаны или старые.

Узнайте больше на PHP документы

0
По вопросам рекламы [email protected]