С помощью srand(time())
генерировать токен для сброса пароля (или для токена CSRF) плохо, потому что токен может быть предсказуемым.
Я прочитал это:
Но я не понимаю, как токен может быть предсказуемым. Я понимаю, что если за одну секунду я много раз сбрасываю свой пароль, я получаю один и тот же токен. У меня есть следующий код:
<?php
srand(time());
$reset_password_token = rand(444444444444,999999999999);
?>
Если я много раз сбрасываю свой пароль за одну секунду, я знаю, что получаю один и тот же токен, но как злоумышленник может воспользоваться этим?
Это ограничивает область их грубой силы. Например, им нужно всего лишь попробовать 60 паролей, если они знают, что кто-то сделал сброс в течение последней минуты.
Но это хуже, чем это. Злоумышленник может войти в любую учетную запись, которую он хочет, инициировав сброс пароля для этой учетной записи. После этого они генерируют несколько токенов, многократно вызывая srand с меткой времени unix для небольшого временного интервала сброса, увеличиваясь каждый раз. Один из этих жетонов должен совпадать, если ваши часы не выключены.
Это предполагает, что требуется 256-битный одноразовый номер.
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()
использует алгоритм, называемый Linear Congruent Generator, который из-за того, как он реализован в PHP 5, работает только с 32-разрядными целыми числами без знака. Оба предоставленных вами номера больше, чем 2**32
, Я не уверен, что это переполнится. Исходный код не очень поучительно в этом случае.
Однако, потому что вы засеваете свои случайные числа time()
, вы столкнетесь с неприятностями. Быстро запустите этот код:
<?php
srand(1431223543);
echo rand()."\n";
Тебе следует увидеть 1083759687
в вашей консоли. Как правило, разница во времени между компьютерами в Интернете довольно мала. Вы, вероятно, могли бы учитывать только возможное дрожание до 2 секунд в каждом часовом поясе, и вам потребовалось бы всего лишь 120 предположений (наихудший случай), чтобы начать прогнозировать случайное число. Навсегда.
Пожалуйста, для всего, что связано с безопасностью вашего приложения, используйте CSPRNG.
Атакующий может узнать / угадать время вашей системы. Конечно, хакер не может знать точную секунду, потому что для большинства серверов это может немного отличаться.
Но скажем, например, ваше местное время:
> echo time();
1431212010
тогда вы можете сделать «хорошее предположение», что семя будет располагаться между 1431212005
а также 1431212015
,
Так что, если вы сможете сделать примерно 10 предположений, очень вероятно, что пароль будет правильным.
Конечно, хакеру все еще нужно знать алгоритм, который «генерирует» пароль. Но для большинства систем это довольно просто и, более того, как всегда в области безопасности, лучше, чтобы в любом случае никто не знал об этой системе. В конце концов, большинство хакеров могут создать свою учетную запись и «проверить», как генерируется пароль, и сначала искать шаблоны.
Кроме того, очень удобный способ взлома пароля — это отправка двух запросов на сброс пароля примерно в одно и то же время: скажем, у вас есть учетная запись X и вы хотите взломать учетную запись Y. В течение миллисекунды вы можете отправить два запроса, один для себя и один для жертвы. Затем вы получите свой пароль и можете использовать его для обеих учетных записей. Как говорит @AlfredRossi, вы можете перечислить все учетные записи на сайте и таким образом взломать большинство учетных записей.
Большинство систем предлагают способ для создания «реальной случайной» (конечно, это спорно, идет ли речь о реальных случайных). Например, путем захвата шума на аудиоканалах или прослушивания других «шумов». Эти значения менее предсказуемы, поскольку вряд ли можно догадаться, какая измеренная интенсивность на аудиоканале находится в нескольких тысячах миль от его / ее местоположения.
Если я сбрасываю свой пароль много раз за одну секунду, я знаю, что получаю один и тот же токен, но как злоумышленник может это использовать?
У вас есть вещь, которую злоумышленник должен «сделать много» неправильно. Злоумышленник может генерировать свои собственные токены в течение разных секунд и пробовать их все в своей учетной записи.