Подтвердить что ты не робот

Генерировать криптографически безопасные случайные числа в php

Функция PHP rand() не дает хороших случайных чисел. Поэтому я начал использовать mt_rand(), который, как говорят, дает лучшие результаты. Но насколько хороши эти результаты? Есть ли какие-либо методы для их улучшения снова?

Моя идея:

function rand_best($min, $max) {
    $generated = array();
    for ($i = 0; $i < 100; $i++) {
        $generated[] = mt_rand($min, $max);
    }
    shuffle($generated);
    $position = mt_rand(0, 99);
    return $generated[$position];
}

Это должно дать вам "идеальные" случайные числа, не так ли?

4b9b3361

Ответ 1

Генераторы псевдослучайных чисел (PRNG) - очень сложный зверь.

Нет никаких реальных "идеальных" генераторов случайных чисел - на самом деле лучшее, что можно сделать из математических функций, является псевдослучайным - они кажутся случайными для большинства целей и целей.

Фактически, выполнение любых дополнительных действий из числа, возвращаемого PRNG, на самом деле не увеличивает его случайность, и на самом деле число может стать менее случайным.

Итак, мой лучший совет: не путайтесь со значениями, возвращаемыми из PRNG. Используйте PRNG, который достаточно хорош для предполагаемого использования, а если нет, то найдите PRNG, который может принести лучшие результаты, если это необходимо.

И, откровенно говоря, похоже, что функция mt_rand использует Mersenne twister, который является довольно хорошим PRNG, так как он, вероятно, будет достаточно хорош для наиболее случайного использования.

Однако Mersenne Twister не предназначен для использования в любых контекстах безопасности. См. этот ответ для решения, которое необходимо использовать, когда вам нужна случайность для обеспечения безопасности.

Edit

В комментариях возник вопрос, почему выполнение операций с случайным числом может сделать его менее случайным. Например, некоторые PRNG могут возвращать более последовательные, менее случайные числа в разных частях бит - high-end может быть более случайным, чем младший.

Следовательно, в операциях, где high-end отбрасывается, а нижний конец возвращается, значение может стать менее случайным, чем исходное значение, возвращаемое из PRNG.

Я не могу найти хорошее объяснение на данный момент, но я основывался на том, что из документации Java для метода Random.nextInt(int), который предназначен для создания довольно случайного значения в указанном диапазоне. Этот метод учитывает разницу в случайности частей значения, поэтому он может возвращать лучшее случайное число по сравнению с более наивными реализациями, такими как rand() % range.

Ответ 2

Быстрый ответ:

В новом PHP7 наконец появилась поддержка криптографически защищенные псевдослучайные целые числа.

int random_int ( int $min , int $max )

Существует также polyfill для PHP5x.

Более длинный ответ


Не существует идеального генератора случайных чисел, и компьютеры используют генератор псевдослучайных чисел для создания последовательностей, которые выглядят случайными. Последовательности выглядят случайными (и передают некоторые тесты случайности), но из-за наличия некоторого алгоритма для его создания вы можете повторить алгоритм с абсолютно одинаковыми состояниями и получить тот же результат.

Тот же совет, что и с криптография, не изобретает ваш собственный шифр, может быть переведен на генераторы случайных чисел и означает, что вы не можете просто получайте множество генераторов случайных чисел, объединенных вместе, и получите возможность получить лучший генератор.


Одним из подмножеств генераторов случайных чисел является криптографически защищенные генераторы случайных чисел:

Требования обычного PRNG также удовлетворяются криптографически защищенный PRNG, но обратное неверно. CSPRNG требования делятся на две группы: во-первых, они проходят статистическую тесты случайности; во-вторых, что они хорошо держатся под серьезными атаки, даже когда часть их начального или запущенного состояния становится доступный злоумышленнику

Итак, это довольно близко к вашему определению "совершенный". Еще один раз без каких-либо условий (кроме обучения криптографии) вы должны попытаться реализовать один из этих алгоритмов и использовать его в своей системе.


Но, к счастью, PHP7 реализовал его,

int random_int ( int $min , int $max )

Генерирует криптографические случайные целые числа, которые подходят для использования где непредвзятые результаты имеют решающее значение (т.е. перетасовка колоды покера).

Источниками случайных являются следующие:

  • В Windows CryptGenRandom() используется исключительно
  • arc4random_buf() используется, если он доступен (обычно BSD)
  • /dev/arandom используется там, где доступно
  • Сценарий getrandom(2) (на новых ядрах Linux)
  • /dev/urandom используется там, где ни одно из указанных выше не доступно

Это приводит к тому, что все предыдущие ответы устарели (и некоторые устарели).

Ответ 3

Я не уверен, что то, что вы сделали, "улучшает" случайность. Из того, что я могу понять, вы генерируете 100 случайных чисел, а затем произвольно выбираете один из них.

Из того, что я помню из своего вероятностного курса, это, вероятно, не увеличивает случайности, как если бы в основе функции генератора лежал основной смещение (mt_rand()), то он все равно будет отражен как-то на выходе.

Ответ 4

Каким образом mt_rand() "bad"?

Например: если он поддерживает определенное число. Допустим, mt_rand (1, 10) поддерживает низкие числа в диапазоне, то есть "1" и "2" происходит в среднем более 10% каждый. Тогда ваше "улучшение" по-прежнему будет страдать от одной и той же проблемы.

Выбор случайного числа из неисправной последовательности по-прежнему будет неисправным.

Ответ 5

<?php
  function random_number(){
      return 4; // return generated number
                // guaranteed to be random
  }
  ?>

Все шутя в сторону, вы начинаете философский вопрос о том, что такое "случайный" или "лучший". В идеале вы хотели бы, чтобы ваши случайные числа имели несколько шаблонов в них в ходе вашей процедуры. Обычно в качестве семени используется системное время, но я также использовал предыдущее случайное число как семя, предыдущее случайное число - как семя. Проблема в том, что с достаточно мощным компьютером и полным знанием работающего оборудования и функции генератора вы сможете предсказать весь набор генерируемых чисел. Таким образом, если бы у вас был достаточно мощный компьютер (некоторые люди поместили Бога в эту категорию), который знал все возможные переменные и функции вселенной, вы могли бы предсказать каждое событие, которое произошло или произойдет. Большинство генераторов случайных чисел прекрасно себя чувствуют, но если вы знаете кого-то, кто может видеть шаблоны, скорее они похожи на парня в Beautiful Mind, и вы должны проверить их в клинике.

По популярному запросу: D

Ответ 6

Я написал cronjob, который периодически получает 1000 номеров из random.org(скажем, один раз в час) и добавляет их в массив PHP. Всякий раз, когда я хочу случайные числа в моем script, я использую mt_rand (0,1000) для вызова числа из этого. Несколько дополнительных микросекунд накладных расходов, но я получаю действительно случайные числа, основанные на естественном атмосферном шуме.

Ответ 7

Все зависит от того, для чего вам нужно это случайное число:) Для меня ShuffleBag является лучшим:)

Ответ 8

Изменить: Мой комментарий больше не действителен. См. Следующий ответ: fooobar.com/questions/296533/...


Я предполагаю, что вы беспокоитесь о распределении mt_rand(). Я тестировал его, и он очень ровный, и обе границы включены.

Я добавил свой тест к комментариям документации для mt_rand() в руководстве по php, но был удален глупым модератором из-за слишком длительной политики, чтобы войти сюда.

Ответ 9

Нет такого понятия, как "идеальное" случайное число. Независимо от того, какое субъективное определение "совершенного" у вас есть. Вы можете достигать псевдослучайного.

Я просто пытался указать вам в правильном направлении. Вы задали вопрос о идеальных случайных числах, даже если совершенные были в кавычках. И да, вы можете улучшить случайность. Вы даже можете реализовать эвристические или "естественные" алгоритмы, такие идеи, как "атмосферный шум", но все же вы не идеальны, никоим образом.

Ответ 10

Если вам не нравится PHP, встроенный в rand(), вам, вероятно, не следует использовать их встроенный shuffle(), поскольку он, кажется, построен на их rand().

Я на полпути уверен, что "отраслевым стандартом" теперь является Fisher-Yates shuffle.

Ответ 11

использовать/dev/ramdom (генератор случайных чисел реального устройства linux) для семени mt_rand

<?
$rnd_dev=mcrypt_create_iv(4, MCRYPT_DEV_RANDOM); //need "apt-get install php5-mcrypt"
$seed=ord(substr($rnd_dev, 0, 1))<<24 |
      ord(substr($rnd_dev, 1, 1))<<16 |
      ord(substr($rnd_dev, 2, 1))<<8 |
      ord(substr($rnd_dev, 3, 1));
mt_srand($seed);
echo mt_rand();
?>

Ответ 12

Я создал класс PHP для генерации случайных чисел и строк PHPRandomValue

Он использует "mcrypt_create_iv (4, MCRYPT_DEV_URANDOM)" для генерации случайных чисел и значений. Я сделал это, работая над криптопроектом, потому что мне нужен безопасный генератор случайных значений. Здесь пример использования

$randomValue = new RandomValue;

$randomValue->randomNumber(): = -3880998

$randomValue->randomNumberBetween(1,10): = 2

$randomValue->randomTextString(): = CfCkKDHRgUULdGWcSqP4

$randomValue->randomTextString(10):  = LorPIxaeEY

$randomValue->randomKey(): = C7al8tX9.gqYLf2ImVt/!$NOY79T5sNCT/6Q.$!.6Gf/Q5zpa3

$randomValue->randomKey(10):  = RDV.dc6Ai/

Ответ 13

Невозможно сгенерировать истинные случайные числа, лучшее, на что вы можете надеяться, является псевдослучайным, что и предоставляет rand(), ваша функция не ближе к случайному, а затем rand(). Взгляните на это http://en.wikipedia.org/wiki/Random_number_generator

Ответ 14

Tru Случайные числа

<?php
for ($i = -1; $i <= 4; $i++) {
    $bytes = openssl_random_pseudo_bytes($i, $cstrong);
    $hex   = bin2hex($bytes);

    echo "Lengths: Bytes: $i and Hex: " . strlen($hex) . PHP_EOL;
    var_dump($hex);
    var_dump($cstrong);
    echo PHP_EOL;
}
?>

а также криптозащита;)

Ответ 15

Хотя ответ был принят много лет назад, я снова его открываю.

Поскольку вся эта случайность зависит от системного времени, пусть беспорядок с системным временем тоже! Время, затрачиваемое операцией на компьютер, на самом деле довольно изменчиво (особенно, если на этом сервере происходит что-то другое), поэтому, если мы воспользуемся этим с помощью microtime... (не удалось найти никаких переносных команд для нанотимов)

$a='';
for (int $i=0; $i<9001; $i++)
{
    usleep(mt_rand(1000,10000));//Also eliminates timing attacks... possibly?
    $a=hash('SHA512',$a.uniqid(mt_rand().microtime(),true));
}
echo $a;

Номинально это имеет 207023 бит энтропии, так как вы добавляете еще 23 бита на каждую итерацию, но там много взаимозависимостей, поэтому, вероятно, на несколько порядков меньше. Все еще очень хорошо.

Знаете ли вы о каких-либо операциях на PHP, которые занимают действительно случайное количество времени? Как... HTTP-запрос на некоторый сайт (кроме RANDOM.org) и измерение времени, которое требуется?

Ответ 16

Используя random.org, вы можете использовать это:

function getToken($length, $min, $max){
    $r = explode('
',file_get_contents('http://www.random.org/integers/num='.$length.'&min='.$min.'&max='.$max.'&col=1&base=10&format=plain'));

    $string = '';
    foreach ( $r as $char ) $string.=$char;
    return $string;
}

это должно дать реальные случайные числа