Безопасное генерирование случайных чисел в PHP

Случай использования: кнопка «Я забыл пароль». Мы не можем найти исходный пароль пользователя, потому что он хранится в хешированной форме, поэтому единственное, что нужно сделать – это создать новый случайный пароль и отправить ему по электронной почте. Для этого требуются криптографически непредсказуемые случайные числа, для которых mt_rand недостаточно хорош, и в целом мы не можем предположить, что служба хостинга предоставит доступ к операционной системе для установки криптографического модуля случайных чисел и т. Д., Поэтому я ищу способ генерировать безопасные случайные числа в самом PHP.

Решение, к которому я придумал, включает в себя хранение начального семени, затем для каждого вызова,

result = seed seed = sha512(seed . mt_rand()) 

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

Я что-то упускаю, или есть более известные решения?

    Related of "Безопасное генерирование случайных чисел в PHP"

    Вы также можете использовать OpenSSL openssl_random_pseudo_bytes, он доступен с PHP 5.3.

      string openssl_random_pseudo_bytes ( int $length [, bool &$crypto_strong ] ) 

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

    http://www.php.net/manual/en/function.openssl-random-pseudo-bytes.php

    Поскольку PHP 7 существует также функция random_bytes

     string random_bytes ( int $length ) 

    http://php.net/manual/en/function.random-bytes.php

    Я настоятельно рекомендую использовать таргетинг / dev / urandom в Unix-системах или крипто-api на платформе Windows в качестве источника энтропии для паролей.

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

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

    Две ошибки не дают права. Система настолько же сильна, как и ее самая слабая часть. Это не лицензия или оправдание, чтобы принять еще большую часть этого неуверенности.


    Вот некоторый код PHP, чтобы получить безопасную случайную 128-битную строку, из этого комментария на php.net от Mark Seecof :

    «Если вам нужны некоторые псевдослучайные биты для безопасности или криптографические цели (яйцо, случайное IV для блочного шифрования, случайная соль для хэша паролей) mt_rand () – плохой источник. На большинстве плат Unix / Linux и / или MS-Windows вы можете получить более высокий класс псевдослучайных битов из ОС или системной библиотеки, например:

     <?php // get 128 pseudorandom bits in a string of 16 bytes $pr_bits = ''; // Unix/Linux platform? $fp = @fopen('/dev/urandom','rb'); if ($fp !== FALSE) { $pr_bits .= @fread($fp,16); @fclose($fp); } // MS-Windows platform? if (@class_exists('COM')) { // http://msdn.microsoft.com/en-us/library/aa388176(VS.85).aspx try { $CAPI_Util = new COM('CAPICOM.Utilities.1'); $pr_bits .= $CAPI_Util->GetRandom(16,0); // if we ask for binary data PHP munges it, so we // request base64 return value. We squeeze out the // redundancy and useless ==CRLF by hashing... if ($pr_bits) { $pr_bits = md5($pr_bits,TRUE); } } catch (Exception $ex) { // echo 'Exception: ' . $ex->getMessage(); } } if (strlen($pr_bits) < 16) { // do something to warn system owner that // pseudorandom generator is missing } ?> 

    NB: в целом безопасно оставлять как попытку чтения / dev / urandom, так и попытку доступа к CAPICOM в вашем коде, хотя каждый из них будет терпеть неудачу на платформе другого пользователя. Оставьте их обоих там, чтобы ваш код был более портативным ».

    PHP поставляется с новым набором функций random_bytes() и random_int() ). Тривиально превратить последнюю функцию в функцию генератора строк:

     <?php /** * Generate a random string, using a cryptographically secure * pseudorandom number generator (random_int) * * For PHP 7, random_int is a PHP core function * For PHP 5.x, depends on https://github.com/paragonie/random_compat * * @param int $length How many characters do we want? * @param string $keyspace A string of all possible characters * to select from * @return string */ function random_str( $length, $keyspace = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' ) { $str = ''; $max = mb_strlen($keyspace, '8bit') - 1; if ($max < 1) { throw new Exception('$keyspace must be at least two characters long'); } for ($i = 0; $i < $length; ++$i) { $str .= $keyspace[random_int(0, $max)]; } return $str; } 

    Если вам нужно использовать это в проекте PHP 5, не стесняйтесь захватить копию random_compat , которая является полиполнением для этих функций.