Безопасная генерация случайных чисел в PHP - PullRequest
33 голосов
/ 25 июля 2009

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

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

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

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

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

Ответы [ 3 ]

59 голосов
/ 11 октября 2009

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

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

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

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


Вот некоторый код PHP для получения безопасной случайной 128-битной строки, из этот комментарий на php.netby 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
}
?>

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

39 голосов
/ 15 июля 2013

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

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

Создает строку псевдослучайных байтов с количеством байтов, определяемых параметром длины. Он также указывает, использовался ли криптографически стойкий алгоритм для создания псевдослучайных байтов, и делает это с помощью необязательного параметра 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

7 голосов
/ 08 декабря 2015

PHP поставляется с новым набором функций CSPRNG (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 , котораяявляется полифилом для этих функций.

...