Making mt_rand() as secure as possible

2019-03-30 00:05发布

问题:

I am writing a raffle program where people have some tickets, which are marked by natural numbers in the range of 1 to 100 inclusive.

I use mt_rand(1,100) to generate the number of the winning ticket, and then this is outputted to the site, so everyone can see it.

Now I did a little research and found out from the Merseene wiki article that:

Observing a sufficient number of iterations (624 in the case of MT19937, since this is the size of the state vector from which future iterations are produced) allows one to predict all future iterations.

Is the current version used by mt_rand() MT19937?

If so, what can I do to make my generated numbers more cryptographically secure?

Thanks in advance :-)

回答1:

The short answer:

If so, what can I do to make my generated numbers more cryptographically secure?

You can simply use a random number generator suited for this task instead of mt_rand().

When PHP 7 comes out, you can use random_int() in your projects when a cryptographically secure random number generator is needed.

"Okay, great, but PHP 7 isn't out yet. What do I do today?"

Well, you're in luck, you have two good options available to you.

Use RandomLib. OR

I've been working on backporting PHP 7's CSPRNG functions into PHP 5 projects. It lives on Github under paragonie/random_compat.

"I don't want to use a library; how do I safely roll my own?"

When it comes to cryptography, rolling your own implementation is usually a poor decision. "Not invented here," is usually a good thing. However, if you're dead set on writing your own PHP library to securely generate random integers or strings, there are a few things to keep in mind:

  1. Use a reliable source of randomness. In order of preference, reading from /dev/urandom should be your first choice, followed by mcrypt_create_iv() with MCRYPT_DEV_URANDOM, followed by reading from CAPICOM (Windows only), and lastly openssl_random_pseudo_bytes().
  2. When reading from /dev/urandom, cache your file descriptors to reduce the overhead of each function invocation.
  3. When reading from /dev/urandom, PHP will always buffer 8192 bytes of data (which, likely, you will not use). Be sure to turn read buffering off (i.e. stream_set_read_buffer($fileHandle, 0);).
  4. Avoid any functions or operations that can leak timing information. This means, generally, you want to use bitwise operators instead of math functions (e.g. log()) or anything involving floats.
  5. Don't use the modulo operator to reduce a random integer to a range. This will result in a biased probability distribution:
  6. A good CSPRNG will not fallback to insecure results. Don't silently just use mt_rand() if no suitable CSPRNG is available; instead, throw an uncaught exception or issue a fatal error. Get the developer's attention immediately.


回答2:

Sorry, but Mersenne Twister was not designed to meet cryptographic requirements. No, you cannot and should not try to fix it, because usually when non-experts try to improve cryptographic functionality, they just end up making things worse.

Php has a long history of problems with its randomness for cryptographic purposes. I'll point out a few references for light reading:

  • I forgot your password: Randomness attacks against PHP applications
  • Cracking PHP's lcg_value()
  • phpwn: Attack on PHP sessions and random numbers

To my knowledge, the best option for secure (pseudo) random number generation in PhP applications is to use openssl_random_pseudo_bytes.



回答3:

mt_rand by its very name is the Mersenne Twister, a non secure random number generator. Furthermore it is often just seeded with a specific time in ms, something that an attacker can simply guess or aim for.

You cannot make the Mersenne Twister secure. So if anywhere possible you should use a secure random number generator seeded by an entropy source. This entropy source is usually obtained from the operating system. An OpenSSL based one should be preferred.

There is absolutely no reason why you would be stuck with MT. PRNG's are just algorithms. There are plenty of libraries that contain secure PRNG's.