2009-06-24 2 views
17

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

Моя идея:

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]; 
} 

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

+0

Это дубликат одного из моих вопросов http://stackoverflow.com/questions/5611/better-random-generating-php – UnkwnTech

+0

В последней версии php есть [криптографически безопасный PRNG] (http: // stackoverflow. ком/а/31443898/1090562). –

+3

Если кто-то читает это, пропустите принятый ответ, потому что [этот ответ правильный] (http://stackoverflow.com/a/31443898/2224584). Если вы застряли на PHP 5, проверьте [random_compat] (https://github.com/paragonie/random_compat). –

ответ

32

Pseudorandom number generators (ПСЧ) очень сложный зверь.

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

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

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

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

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

Редактировать

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

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

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

+1

Как он может стать «менее случайным»? – karim79

+4

karim: Поскольку все PRNG основаны на вычислениях, которые генерируют только случайные числа, есть определенные недостатки. В принципе генерация «случайных» чисел идет вразрез со всем, что может сделать компьютер, поскольку компьютеры - это конструкции-детерминированные машины. В зависимости от того, какие вычисления выполняются для чисел для генерации случайных битов, есть некоторые, которые показывают статистически достоверную случайность, а некоторые - нет. Это зависит от вашего генератора. LCG имеют слабые разряды, другие типы имеют слабые высокие бит, другие даже не проявляют слабости. Это очень сложная тема. – Joey

+1

coobird: Java Random.nextInt (int) делает _not_ для более слабых бит. Что он делает, это устранение смещения из-за операции модуля, которая предпочла бы меньшие значения. Мне потребовалось два дня, чтобы понять, почему это работает, но это очень элегантно. Но 600 символов слишком коротки для этого. Часть, которая отбрасывает младшие биты (из-за меньшей случайности), выполняется в Random.next (int): return (int) (seed >>> (48 бит)). Как вы можете видеть, туда возвращается не более 32 из 48 бит LCG, что делает хорошую работу, устраняя «слабые» младшие биты. – Joey

1

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

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

+0

Но даже если есть только псевдослучайные числа, вы можете улучшить случайность, не так ли? – caw

+0

Случайность - это просто обратная наша способность прогнозировать выход ... поэтому идеальная случайная двоичная цифра составляет всего 50% «случайный». Для создания «истинных» случайных чисел требуется исключить предсказуемые шаблоны между числами, и лучший способ сделать это - использовать процессы, которые мы, люди, действительно не очень хорошо понимаем; как радиоактивный распад и атмосферный шум. Эти источники доступны в Интернете, посмотрите HotBits и Random.org для этих источников соответственно. – Steve

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

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

By popular demand: D

+4

Не уверен, что люди, которые не читают xkcd, получат шутку. Вероятно, было бы лучше связать его. – Davy8

+0

Я должен сделать так, чтобы вы не связывали его. – UnkwnTech

+0

вместо этого я просто вставляю изображение – UnkwnTech

17

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

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

+0

Вы поняли это правильно. Спасибо за Ваш ответ. Теперь я знаю, что я не могу улучшить случайность с дальнейшими расчетами. – caw

+0

Что делать, если у вас было два разных алгоритма RNG? Вы улучшили ситуацию? – Carbon

13

Каким образом mt_rand() «плохой»?

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

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

+0

Да, это именно то, о чем я думал. – Peter

+0

Спасибо, хорошо объяснил. – caw

+0

+1 Очень хорошо сделано! Хорошее объяснение! – Melsi

-1

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

+0

Вы имеете в виду mt_rand(), функция rand() в php была признана ошибочной. – Gerry

+0

mt_rand() и rand() больше не имеют недостатков, чем любой другой psuedo-RNG, насколько я знаю. – UnkwnTech

+3

Разница заключается в алгоритме и доказуемых статистических свойствах случайных чисел. И rand() does * not * достаточно для многих приложений. Кроме того, Mersenne Twister достаточно быстр и генерирует намного более качественные номера, поэтому для людей, не имеющих глубоких знаний о поле, можно смело предположить MT19937 вместо встроенного rand(). – Joey

1

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

Я нахожусь на полпути, что «промышленный стандарт» перетасовывает теперь Fisher-Yates shuffle.

2

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

2

Edit: Мой комментарий больше не действует. Пожалуйста, смотрите следующий ответ: https://stackoverflow.com/a/31443898/109561


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

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

+0

Я должен также обратите внимание, что для истинных случайных чисел (если есть такая вещь) они станут более равномерно распределены, так как число итераций приближается к бесконечности. Хотя это верно и для mt_rand(), из моих тестов, похоже, в среднем намного быстрее получить более равномерное распределение. – Gerry

+1

Все зависит от того, какое распределение следует за случайными числами. Это равномерное распределение, тогда да. Но существуют специализированные PRNG, которые генерируют случайные числа и в других дистрибутивах (нормальный, экспоненциальный, ...), что экономит ваши усилия по изменению распределения (так как для некоторых дистрибутивов нет простых/хороших/эффективных способов). Если смотреть только с одним измерением, rand() и mt_rand() должны выглядеть одинаково с точки зрения «случайности». Это начинается с 3-х измерений вверх, где вещи получают удовольствие от LCG :-) – Joey

5

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

+2

Это вводит возможность повторного использования одних и тех же чисел в массиве до его обновления, что представляет собой * намного меньший набор возможных значений, чем полный диапазон 32-битных целых чисел, даже если тысячи чисел поступают из большего диапазона. Лучшим методом было бы рассматривать массив как очередь; добавляя новые значения по мере необходимости, всегда используя первый элемент и отбрасывая его потом. – gapple

+0

Я генерировал случайные числа, используя критерии «num = 10000 & min = 1 & max = 1000000» на random.org и получил 50 повторяющихся значений. Таким образом, это кажется его неслучайным по своей природе. –

1

использование/DEV/ramdom (линукс устройство верно генератор случайных чисел) семена 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(); 
?> 
+2

Без внешнего источника шума компьютер не может иметь «истинный генератор случайных чисел», и если это так, зачем использовать его для засева менее случайного источника? Если у вас уже есть «истинные» случайные числа, почему бы просто не использовать их? – Steve

-4

Использование 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; 
} 

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

номера
+0

Я генерировал случайные числа, используя критерии «num = 10000 & min = 1 & max = 1000000» на random.org и получил 50 повторяющихся значений. Таким образом, это кажется его неслучайным по своей природе. –

-1

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; 
} 
?> 

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

-2

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

Поскольку вся эта случайность зависит от системного времени, давайте также испортить системное время! Количество времени, которое занимает операция на компьютере, на самом деле довольно изменчиво (особенно, если на этом сервере происходит что-то другое), поэтому, если мы воспользуемся этим с помощью 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) и измерение времени, которое требуется?

0

Я сделал класс 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/ 
22

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

В новом PHP7 Eсть финально опора для cryptographically secure pseudo-random integers.

int random_int (int $min , int $max) 

Существует также polyfill for PHP5x.

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


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

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


Один из подмножеств генераторов случайных чисел является cryptographically secure random number generators:

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

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


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

int random_int (int $min , int $max) 

Формирует криптографических случайных чисел, которые подходят для использования , где объективные результаты являются критическими (т.е. перетасовки Poker палубы).

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

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

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

+5

Это ** правильный ** ответ. : D –

+0

openssl_random_pseudo_bytes существует с 2009 года/5.3.0 .. просто оберните его в что-то, что проверяет сильное_копирование, например 'function f ($ len) {$ ret = openssl_random_pseudo_bytes ($ len, $ strong); if (! $ strong) {throw new \ RuntimeException ('$ crypto_strong failed!');} return $ ret;} ' – hanshenrik

Смежные вопросы