预测PHP的rand()的输出


21

我已经读过很多资料,PHP的rand()的输出作为PRNG是可以预测的,我之所以接受它是因为,因为我在很多地方都看过它。

我对概念验证很感兴趣:如何预测rand()的输出?通过阅读本文,我了解到随机数是从指针(种子)开始的列表中返回的数字,但是我无法想象这是如何可预测的。

有人可以合理地找出在几千个猜测中的给定时间点通过rand()生成了什么随机数吗?甚至一万个猜测?怎么样?

这是因为我看到了一个使用rand()为丢失密码的用户生成令牌的auth库,并且我认为这是一个潜在的安全漏洞。从那以后,我已经用哈希openssl_random_pseudo_bytes(),原始哈希密码和microtime 的混合哈希代替了该方法。完成此操作后,我意识到,如果我在外面看,即使知道它是rand()的md5,也不知道如何猜测该令牌。


“但是我无法想象这是如何可预测的”?您需要先阅读“ en.wikipedia.org/wiki/Linear_congruential_generator ”,以便可以开始想象它的可预测性。然后,您可以修改问题以消除惊讶,并转向更实际的反向工程PHP问题。 rand函数来源以了解其工作原理
S.Lott

“我认为这是一个潜在的安全漏洞”?仅当Evil Hacker可以获取某些用户的随机密码时,才使用彩虹表撤消MD5哈希以恢复原始(哈希前)值,然后保证他们提出了下一个密码请求。我想从理论上讲是可能的。但前提是他们有一个随机数的工作彩虹表。
S.Lott

@ S.Lott-它与密码无关。系统允许您重置密码并通过电子邮件向您发送URL中使用的令牌。令牌是通过MD5(rand())生成的。如果您可以预测rand()的输出,则可以更改任何人的密码,而无需获取原始哈希值或知道原始值。
埃里克(Erik),

@Erik。对。如果有帮助,请用“随机令牌”替换“随机密码”。仅当有人可以展开MD5哈希值以恢复随机数并确保他们将获得下一个随机数时,才能滥用该令牌。预测下一个兰特只是一小部分。撤消MD5是困难的部分。
S.Lott,

1
请注意,MD5(rand())仅具有与rand()相同的安全性。为涉及的非常有限的数字集建立一个MD5(rand())-> rand()查找表是很实际的。使用rand()的有限域,您可以尝试简单的暴力破解,除非有适当的机制来防止重复尝试。
2011年

Answers:


28

从中猜测下一个值的rand能力与确定所srand调用内容的能力有关。特别是,以预定数量播种会srand导致可预测的输出!在PHP交互式提示符下:

[charles@charles-workstation ~]$ php -a
Interactive shell

php > srand(1024);
php > echo rand(1, 100);
97
php > echo rand(1, 100);
97
php > echo rand(1, 100);
39
php > echo rand(1, 100);
77
php > echo rand(1, 100);
93
php > srand(1024);
php > echo rand(1, 100);
97
php > echo rand(1, 100);
97
php > echo rand(1, 100);
39
php > echo rand(1, 100);
77
php > echo rand(1, 100);
93
php > 

这不仅仅是fl幸。大多数PHP版本*在大多数平台**会生成序列97,97,39,77,93时,srand“d与1024。

要明确的是,这不是PHP的问题,这是其rand自身实现的问题。在使用相同(或相似)实现的其他语言(包括Perl)中也会出现相同的问题。

诀窍是,任何理智的PHP版本都将预先植入srand“未知”值。哦,但这并不是真正未知的。来自ext/standard/php_rand.h

#define GENERATE_SEED() (((long) (time(0) * getpid())) ^ ((long) (1000000.0 * php_combined_lcg(TSRMLS_C))))

因此,这是一个数学运算符time(),其中包含PID以及PID的结果php_combined_lcg,它们在中定义ext/standard/lcg.c。我不会在这里进行c&p,因为,我的眼睛发呆,所以我决定停止狩猎。

有点谷歌搜索表明PHP的其他区域没有最好的随机性生成属性,并呼吁在php_combined_lcg这里脱颖而出,尤其是以下分析:

此函数(gettimeofday)不仅使我们在银盘上获得了精确的服务器时间戳,而且如果我们要求“更多熵”(来自PHP uniqid),它还会添加LCG输出。

是啊uniqid。似乎值php_combined_lcg是在调用uniqid第二个参数设置为真值后查看生成的十六进制数字时所看到的。

现在,我们在哪里?

哦是的 srand

因此,如果您尝试从中预测随机值的代码没有调用srand,则需要确定由提供的值php_combined_lcg,您可以通过调用来(间接获得)该值uniqid。根据手中的价值,这是可行的,以蛮力价值的休息- time(),PID和一些数学。链接的安全性问题是关于中断会话的,但是相同的技术在这里也适用。再次,从文章:

这是上面概述的攻击步骤的摘要:
  • 等待服务器重启
  • 获取唯一值
  • 蛮力从此RNG种子
  • 轮询在线状态以等待目标出现
  • 将状态轮询与uniqid轮询交错,以跟踪当前服务器时间和RNG值
  • 使用轮询中建立的时间和RNG值间隔对服务器进行暴力会话ID

只需根据需要替换最后一步。

(此安全问题是在比我们当前的版本(5.3.6)更早的PHP版本(5.3.2)中报告的,因此,uniqid和/或php_combined_lcg已更改的行为很可能,因此该特定技术可能不再可行。 YMMV。)

另一方面,如果您要尝试人工生成的代码调用srand,那么除非它们使用的结果比的结果好很多倍,否则php_combined_lcg您可能会更容易地猜测出值并为本地设置种子编号正确的发电机。大多数会手动调用的人srand也不会意识到这是多么可怕的想法,因此不太可能使用更好的价值。

值得注意的是,mt_rand同样的问题也困扰着它。mt_srand具有已知值的播种也会产生可预测的结果。基于您的熵openssl_random_pseudo_bytes可能是一个更安全的选择。

tl; dr:为了获得最佳结果,请不要植入PHP随机数生成器,并且出于良善起见,请不要uniqid向用户公开。两者之一或两者都做可能会使您的随机数更容易猜测。


PHP 7更新:

PHP 7.0引入random_bytesrandom_int作为核心功能。他们使用基础系统的CSPRNG实现,从而使它们摆脱了种子随机数生成器所具有的问题。它们实际上与相似openssl_random_pseudo_bytes,只是不需要安装扩展程序。 Polyfill可用于PHP5


*:Suhosin安全补丁会更改的行为,randmt_rand始终在每次调用时重新植入种子。Suhosin由第三方提供。默认情况下,某些Linux发行版将其包含在其官方PHP软件包中,而其他发行版则将其作为选项,而其他发行版则完全忽略了它。

**:根据所使用的平台和底层库调用,将生成与此处记录的序列不同的序列,但是除非使用Suhosin补丁,否则结果应仍可重复。


谢谢Charles-在您的答案和阅读Tangurena上的线性同余生成器的链接之间,我觉得我能更好地掌握它。我已经“知道”以这种方式使用rand()是个坏主意,但知道我知道为什么
埃里克(Erik)

哇,道具为您提供了详尽详尽的答案,谢谢!
David Hobs 2014年

10

为了直观地说明该rand()功能的非随机性,以下是所有像素均由“随机”红色,绿色和蓝色值组成的图像:

随机RGB值

图像中通常不应有任何图案。

我尝试srand()使用不同的值进行调用,但不会更改此函数的可预测性。

请注意,两者都不是密码安全的,不会产生可预测的结果。


7

PHP的rand()的输出是可预测的,因为它是PRNG

它是线性同余生成器。这意味着您具有一个有效的功能:NEW_NUMBER = (A * OLD_NUMBER + B) MOD C。如果您绘制NEW_NUMBER与OLD_NUMBER的图表,您将开始看到对角线。PHP的RAND文档中的一些注释提供了有关操作方法示例。

这是因为我看到了一个使用rand()为丢失密码的用户生成令牌的auth库,并且我认为这是一个潜在的安全漏洞。

在Windows计算机上,RAND的最大值为2 ^ 15。这使攻击者只有32,768种检查可能性。

有人可以合理地找出在几千个猜测中的给定时间点通过rand()生成了什么随机数吗?甚至一万个猜测?怎么样?

尽管本文并不完全是您要找的文章,但它显示了一些研究人员如何利用现有的随机数生成器实现并利用它在Texas Holdem上赚钱。有52个!可能会打乱的套牌,但是该实现使用了32位随机数生成器(这是Windows机器上mt_getrandmax中的最大数字),并以自午夜以来的毫秒数播种了该种子。这将可能改组的牌组的数量从大约2 ^ 226减少到大约2 ^ 27,从而可以实时搜索并知道处理了哪个牌组。

完成此操作后,我意识到,如果我在外面看,即使知道它是rand()的md5,也不知道如何猜测该令牌。

我建议在SHA-2系列中使用某些东西,因为联邦调查局认为md5损坏了。有些人使用Google解密md5哈希,因为它们是如此普遍。只是对某些东西进行哈希处理,然后将哈希值放入Google搜索中-基本上,Google已成为一个巨大的彩虹表


1

准确地说,给定一个随机生成的数字,下一个数字是相对可预测的。只能有这么多的数字。但这并不意味着您可以猜到它,更多的是您可以很快地编写出一个可以运行的程序。


1
我认为下一个数字完全是确定性的。不是“相对”而是绝对。伪随机数生成器的问题是序列将通过统计检验。两个完全相同的相邻数字虽然具有确定性,但可能具有与实际随机数字相同的统计属性。
S.Lott

1
下一个数字完全是确定性的。这就是伪随机数生成器中“伪”的含义。另一方面,确定下一个数字所需的信息实际上很难获得。
Rein Henrichs

@ S.Lott-我的印象是,一个数字可能会在2 ^ 32个可能的输出中多次出现,并且每次出现后都可能跟随一个不同的数字。但是给定X的种子,返回Y的结果,则下一个结果将始终相同。因此,实际上,Y后面可能有少数数字。自从我真正研究PRNG以来已经有很长时间了。
pdr
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.