Php 为什么srand(time())是个坏种子?

Php 为什么srand(time())是个坏种子?,php,security,random,passwords,entropy,Php,Security,Random,Passwords,Entropy,使用srand(time())为密码重置(或CSRF令牌)生成令牌是错误的,因为令牌是可预测的 我读到: 但我不明白这个代币是如何被预测的。我明白,如果在一秒钟内多次重置密码,我会得到相同的令牌。我有以下代码: <?php srand(time()); $reset_password_token = rand(444444444444,999999999999); ?> <?php srand(time()); $reset_password_token = r

使用
srand(time())
为密码重置(或CSRF令牌)生成令牌是错误的,因为令牌是可预测的

我读到:

但我不明白这个代币是如何被预测的。我明白,如果在一秒钟内多次重置密码,我会得到相同的令牌。我有以下代码:

<?php

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

?>
<?php

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

?>


如果我在一秒钟内多次重置密码,我知道我得到了相同的令牌,但攻击者如何利用此令牌?

这限制了他们的暴力范围。例如,如果他们知道有人在最后一分钟内重置了密码,他们只需要尝试60个密码

但比这更糟糕。攻击者可以通过启动该帐户的密码重置,进入他们想要的任何帐户。在此之后,他们通过在重置前后的某个小时间窗口内使用unix时间戳反复调用srand来生成一些令牌,每次都递增。其中一个令牌必须匹配,除非您的时钟偏离时间范围。

时间范围攻击 攻击者可以知道/猜测系统的时间。当然,黑客不可能知道确切的秒数,因为对于大多数服务器来说,秒数可能略有不同

但举例来说,你的当地时间是:

> echo time();
1431212010
然后,您可以“很好地猜测”种子将位于
1431212005
1431212015
之间

因此,如果你能猜10次,密码很可能是正确的

当然,黑客仍然需要知道“生成”密码的算法。但对于大多数系统来说,这相当简单,而且在安全性方面,最好不要对系统了解太多。毕竟,大多数黑客可以建立自己的帐户,并“检查”密码是如何生成的,然后首先查找模式

如果黑客自己有账户 破解一个人密码的一个非常方便的方法是在几乎同时发布两个密码重置请求:假设你有一个帐户X,你想破解帐户Y。在一毫秒内,你可以提交两个请求,一个为你自己,一个为受害者。接下来,您将收到您的密码,您可以将其用于两个帐户。正如@AlfredRossi所说,你可以进一步列举网站的所有账户,从而攻击大多数账户

解决 大多数系统提供了一种生成“真实随机”的方法(当然,我们是否谈论真实随机是有争议的)。例如,通过捕获音频通道中的噪声或收听其他“噪声”。这些值的可预测性较低,因为人们很难猜到音频通道的测量强度在距离他/她的位置几千英里的地方。

好的解决方案 这假设需要256位nonce

  • 随机字节(32)
    (PHP 7.0.0+)
  • openssl\u随机\u伪\u字节(32)
  • mcrypt\u create\u iv(32,mcrypt\u DEV\u uradom)
  • 阅读
    /dev/uradom
  • #4的代码片段:

    从理论上讲,只有5555个可能的值。不幸的是,实际数字要低得多

    rand()
    使用一种称为线性同余生成器的算法,由于它在PHP5中的实现方式,该算法仅适用于无符号32位整数。您提供的两个数字都大于
    2**32
    。我不确定它是否会溢出。在这种情况下不是很有启发性

    但是,由于您正在使用
    time()
    播种随机数,因此您将遇到麻烦。快速运行以下代码:

    <?php
    
    srand(1431223543);
    echo rand()."\n";
    
    
    如果我在一秒钟内多次重置密码,我知道我得到了相同的令牌,但攻击者如何利用这一点


    你知道攻击者必须“做很多”错事。攻击者可以在许多不同的时间内生成自己的令牌,并对您的帐户进行所有尝试。

    Supose我确切知道时间戳和算法生成器(如我的示例所示的范围号)。如果我理解,如果我尝试这样做:
    while(1){//生成一个新令牌并在网站srand中捕获时间戳($sametimestamp);$reset_password_token=rand(44444444444499999999);//在网站睡眠中测试令牌(3);//使用新的时间戳再次测试}
    我能猜到令牌吗?是的。试试看。兰德(4444444444449999999999)的输出是由输入到srand的值决定的。我尝试了这个,但它不起作用。我想,如果我提前5分钟生成多个带有时间戳的令牌,可能是工作?这里的“不工作”是什么意思?你想做什么?我生成一个新的令牌,然后在目标网站中捕获时间戳。在我的服务器中,我生成了一个具有相同rand目标值范围和相同srand的令牌,我等待2/3秒,然后再试一次。
    大多数系统提供了一种生成“真实随机”的方法(当然,我们是否谈论真实随机是有争议的)
    更切题地说,对于密码学来说。一个正在运行的递增整数,添加到timeseed中,反击两种攻击?@Wortex 17:如果黑客自己有一个帐户,他/她可以尝试重建该计数器。此外,反击可能是一个糟糕的词语选择。安全不是一个开/关的故事,关键是在合理的范围内将风险最小化。种子只是一个问题。使用
    rand
    本身,即使有不可预测的种子,也是一个安全漏洞。除了使用
    /dev/uradom
    之外,
    /dev/random
    很有趣,因为它试图引导高熵,因此,它会阻止读取,直到熵池中有足够的位可用。通过查找服务器所在的位置,从而“猜测”时区,也可以减少猜测次数。如果你做了一些经过计算的猜测,可能需要更少的猜测。@CommuSoft你当然是对的。事实上,你可以
    <?php
    
    srand(1431223543);
    echo rand()."\n";