In 2014 an exploit was discovered in Firefox for Android that allowed malicious applications access to sensitive user data. The cause? An unfortunately predictable PRNG called
Math.random() function is your default PRNG.
Don’t worry, though. We’ve got your back.
Here’s a breakdown of exactly where
Math.random() goes astray, and some possible PRNG alternatives you can use to make your projects more secure.
There’s really nothing random about
Math.random(). By definition, PRNGs generate numbers deterministically based on a set of initial seed value: they can only approximate randomness. While there are PRNGs that come a stone’s throw from true randomness (we’ll get to those),
Math.random() is widely regarded as sub-par.
What does this mean?
But in the event you’re currently using
Math.random() where unique values are critical—to create unique session IDs, generate values across active users, or for encryption—there could be major security implications.
Luckily, for these security-centered scenarios you have the option of cryptographically secure pseudorandom number generators (CSPRNGs). These are designed to resist a would-be attacker’s ability to identify the seed value and predict subsequent outputs in a sequence.
Since security isn’t the only place where random number generation is necessary, it’s important to understand the non-cryptographic alternatives to
With that in mind, we’ve put together this list of more powerful, easy-to-implement PRNGs for you to use in your application:
Xorshift random number generators create sequences by “repeatedly taking the exclusive of a number with a bit shifter version of itself.” It passes more statistical tests than
Math.random() and, because of the way it structures sequences, it’s much faster.
According to the (in no way biased) chart below, PCG random number generators are the cream of the crop. They’re difficult to predict, extremely fast, compact, and statistically excellent.
While the random number generators listed above are invariably better than
Math.random(), their lack of a cryptographic component ultimately renders them inferior to CSPRNGs when used for security.
By default, the Node.js library contains
crypto.randomBytes(), a CSPRNG that uses entropy from the underlying operating system to create near-true randomness. For example, on Linux
crypto.randomBytes() takes the entropy from /dev/urandom, and generates random bytes which can be used to create secure pseudorandom numbers.
Stacked up against
crypto.randomBytes() looks even more impressive: it generates a table of unique possible random values on each call compared to a static table generated only once by
Math.random(): Not completely useless
Math.random() isn’t as powerful a PRNG as Xorshift, PCG, or the Mersenne Twister, it does still generate pseudorandom numbers. If you aren’t using your PRNG to create and track sessions or for some other application in which an increased chance of recurring values could be cataclysmic,
Math.random() could make sense.
That being said, any of the other three PRNGs would be better: they’re faster, more powerful, more efficient. And, in a security context, not even these options will cut it: the cryptographic alternative is a necessity.