0

有人知道是否有人使用 rand() 的弱点来预测利用它的时间或事件吗?比如生成代币或在电子游戏中作弊?

由于在 PHP 7 之前,rand() 非常容易破解。事实上,这里有一些 C 代码,归功于 Peter Selinger,它可以预测给定种子的值:

#include <stdio.h>

#define MAX 1000
#define seed 1

main() {
  int r[MAX];
  int i;

  r[0] = seed;
  for (i=1; i<31; i++) {
    r[i] = (16807LL * r[i-1]) % 2147483647;
    if (r[i] < 0) {
      r[i] += 2147483647;
    }
  }
  for (i=31; i<34; i++) {
    r[i] = r[i-31];
  }
  for (i=34; i<344; i++) {
    r[i] = r[i-31] + r[i-3];
  }
  for (i=344; i<MAX; i++) {
    r[i] = r[i-31] + r[i-3];
    printf("%d\n", ((unsigned int)r[i]) >> 1);
  }
}

那么再一次,有没有使用这个弱点来预测下一个随机数并利用某些东西?

谢谢!

4

1 回答 1

0

在 PHP 7 之前,PHP 使用Linear Congruential Generator算法来生成随机数或简称 LCG。该算法的工作原理如下:

 next_random = (previous_random * a + c) % m
 previous_random = next_random

当你第一次做随机数时,显然没有previous_random 数。这就是我们提供种子的原因。因此,种子只是第一个 previous_random 值。

现在,我们知道了算法,但我们需要知道a,cmPHP 使用的值。我相信每个版本的 PHP 都使用不同的值。但是假设我们不知道这些值,我们如何猜测这个值。就我而言,我使用的是 PHP 5.6.15 Windows。

srand(0);
var_dump(rand());  // 12345
var_dump(rand());  // 5758

所以,m = getrandmax () + 1。由于我们的种子是 0,所以我们的c = 12345. 为了得到值a,我们可以使用简单的循环来猜测a

$m  = getrandmax () + 1;
for($a = 0; $a < $m; $a++)
   if ((($a * 12345 + 12345) % $m) == 5758) 
       var_dump($a);  // in my case, 20077

或者你可以获得a这样的价值

srand(0); rand(); // 12345
srand(1); rand(); // 32422
// so a = 32422 - 12345 = 20077

现在,我可以编写与当前 PHP 版本相同的随机函数。

class visal_rnd 
{
    function __construct($seed = 0) {
        $this->seed = $seed;
    }

    function rnd() {
        $this->seed = ($this->seed * 20077 + 12345) % 32768;
        return $this->seed;
    }
}

然而

我能够预测我自己的 PHP 版本,因为我对我当前的环境有很多了解,我知道一些以前的随机,我知道种子。如果攻击者的知识几乎为零,就不容易攻击。

梅森捻线机

PHP 7.0+ 默认使用Mersenne Twister。比线性同余生成器要猜测的参数更多。所以,它需要更多的知识。

线性同余生成器不好吗?

取决于您向公众公开了多少信息。如果您只生成一个随机数并且攻击者不知道aprevious_random和。攻击者不可能预测下一个随机数。cm

于 2017-07-08T12:07:53.813 回答