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.
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 Math.random(), 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().