php中常用的随机数产生函数是rand()和mt_rand()。但是生成的是伪随机数,不能应用于生成安全令牌、核心加解密key等。否则会产生一些安全问题。
何时自动播种
都知道,同一个种子产生的随机序列完全相同,因此种子在随机数中起着至关重要的地位。
自 PHP 4.2.0 起,不再需要用 srand() 或 mt_srand() 给随机数发生器播种 ,因为现在是由系统自动完成的。
那么问题是,php中何时会自动播种呢?如果每次调用随机数都会自动播种那么破解出种子也没有意义。
查看源码发现,每次调用mt_rand()都会先检查是否已经播种。如果已经播种就直接产生随机数,否则系统进行自动播种。也就是说每个php进程期间,只有第一次调用mt_rand()会自动播种。接下来都会根据这个第一次播种的种子来生成随机数。
那么接下来进行测试。
首先是在本地命令行:1
$ php -r "echo mt_rand().' '.mt_rand().' '.mt_rand().' '.mt_rand();"
生成了4个随机数:272444184 1241931419 1575764393 1197993479。
那么接下来用 php_mt_seed 工具来爆破种子,此工具可以根据第一个生成的随机数来猜测可能的种子,其实就是枚举测试了。
1 | $ ./php_mt_seed 272444184 |
一共找到了10个种子,选择自己的php版本,挨个手动播种进行测试:1
$ php -r "mt_srand(2294193663); echo mt_rand().' '.mt_rand().' '.mt_rand().' '.mt_rand();"
发现2294193663这个种子结果完全一致。
这种方式每个进程期间共用一个种子,每个php命令行都是一个进程。如果再重复生成随机数的过程,由于不是同一个进程种子当然不一样。
那么web服务器中的php呢?由于php的运行模式、web服务器种类(apache、nginx)等不同,有可能每个进程只处理一个请求,也有可能一个进程处理多个请求之后才会被回收,当然超时也会被回收。这块查了一些资料,网上说的也不是很清楚,具体的还不是很明白。