Почему srand (time()) является плохим семенем?

Использование srand(time()) для генерации токена для пароля reset (или для токена CSRF) плохо, потому что токен может быть предсказуемым.

Я прочитал:

Но я не понимаю, как токен может быть предсказуемым. Я понимаю, что если через секунду я reset мой пароль много раз получаю тот же токен. У меня есть следующий код:

<?php

srand(time());
$reset_password_token = rand(444444444444,999999999999);

?>

Если я reset мой пароль много раз за одну секунду, я знаю, что получаю тот же токен, но как злоумышленник может воспользоваться этим?

Ответ 1

Это ограничивает объем их грубой силы. Например, им нужно всего лишь выполнить 60 паролей, если они знают, что кто-то сделал reset в течение последней минуты.

Но это хуже, чем это. Злоумышленник может войти в любую учетную запись, которую они хотят, инициировав пароль reset для этой учетной записи. После этого они генерируют несколько токенов, многократно вызывая srand с временной отметкой unix для небольшого временного интервала вокруг reset, увеличивая каждый раз. Один из этих токенов должен совпадать, если ваши часы не выключены.

Ответ 2

Хорошие решения

Предполагается, что требуется 256-битное nonce.

  • random_bytes(32) (PHP 7.0.0 +)
  • openssl_random_pseudo_bytes(32)
  • mcrypt_create_iv(32, MCRYPT_DEV_URANDOM)
  • Чтение из /dev/urandom

Фрагмент кода для # 4:

<?php
function getRandom($bytes)
{
    // Read only, binary safe mode:
    $fp = fopen('/dev/urandom', 'rb');

    // If we cannot open a handle, we should abort the script
    if ($fp === false) {
        die("File descriptor exhaustion!");
    }
    // Do not buffer (and waste entropy)
    stream_set_read_buffer($fp, 0);

    $entropy = fread($fp, $bytes);
    fclose($fp);
    return $entropy;
}

Плохие решения

  • mt_rand()
  • rand()
  • uniqid()
  • microtime(true)
  • lcg_Value()

Что делает хорошее решение?

Хорошее решение должно использовать криптографически защищенный генератор псевдослучайных чисел (CSPRNG). В операционных системах, основанных на Unix, это может быть достигнуто путем прямого чтения из /dev/urandom.

Но я не понимаю, как токен может быть предсказуемым.

Этот раздел был подробно рассмотрен ранее.

У меня есть следующий код:

<?php

srand(time());
$reset_password_token = rand(444444444444,999999999999);

?>

В теории было бы доступно только 555555555555 возможных значений. К сожалению, фактическое число намного ниже.

rand() использует алгоритм, называемый линейным конгруэнтным генератором, который из-за того, как он реализован в PHP 5, работает только с 32-битными целыми числами без знака. Оба числа, которые вы указали, больше, чем 2**32. Я не уверен, что это переполнится. Исходный код в этом случае не очень полезен.

Однако, поскольку вы высеваете свои случайные числа с помощью time(), вы столкнетесь с проблемами. Быстро выполните этот код:

<?php

srand(1431223543);
echo rand()."\n";

Вы должны увидеть 1083759687 в консоли. Как правило, разница во времени между компьютерами в Интернете довольно маленькая. Вероятно, вы могли бы объяснить только возможный дрожание до 2 секунд в каждом часовом поясе, и вам потребуется всего 120 догадок (худший случай), чтобы начать прогнозирование вывода случайных чисел. Навсегда.

Пожалуйста, для чего-либо вообще связанного с безопасностью вашего приложения, используйте CSPRNG.

Ответ 3

Атака временных рамок

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

Но скажем, например, ваше местное время:

> echo time();
1431212010

тогда вы можете сделать "хорошее предположение", что семя будет находиться между 1431212005 и 1431212015.

Итак, если вы можете сделать 10 догадок, шансы, скорее всего, будут правильными.

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

Если у хакера есть учетная запись

Действительно удобный способ взломать пароль, кроме того, отправляет два пароля reset запросы примерно в тот же момент: скажем, у вас есть учетная запись X, и вы хотите взломать учетную запись Y. В течение миллисекунды вы можете отправить два запроса, один для себя и один для жертвы. Затем вы получите свой пароль, и вы можете использовать его для обеих учетных записей. Как говорит @AlfredRossi, вы также можете перечислить все учетные записи веб-сайта и, таким образом, взломать большинство учетных записей.

Решение

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

Ответ 4

Если я reset мой пароль много раз в одну секунду, я знаю, что получаю тот же токен, но как злоумышленник может использовать это?

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