Is Math.random() cryptographically secure?
Asked Answered
S

7

63

How good are algorithms used in Javascript Math.random() in different browsers? Is it okay to use it for generating salts and one-time passwords?

How many bits from one random I can use?

Scarborough answered 13/4, 2011 at 15:31 Comment(0)
W
58

Nope; JavaScript's Math.random() function is not a cryptographically-secure random number generator. You are better off using the JavaScript Crypto Library's Fortuna implementation which is a strong pseudo-random number generator (have a look at src/js/Clipperz/Crypto/PRNG.js), or the Web Crypto API for getRandomValues

Wsan answered 13/4, 2011 at 15:36 Comment(7)
As an addendum, though, you don't need a cryptographically secure PRNG to generate a salt. Salts need only be unique, and generated nondeterministically.Uncanonical
Good point but again, a short password + salt may fall victim to rainbow tables. Where cryptography is involved, it is always favorable to use crypto-grade RNGs.Wsan
@Teoman The length of the salt and password are independent of the source of the salt, though. And yes, cryptographically secure is generally a safer bet.Uncanonical
It doesn't have to be short actually, being predictable (as in random()) makes it a very good target for dictionary/table attacks..Wsan
@Teoman That's why I said 'deterministic'. It's only predictable if either the first bits provide information about the subsequent ones, reducing entropy - which only very poor RNGs like LCGs will do - or if the salt can be predicted from other information such as the password. Neither of those are the case for even half-decent non-cryptographic PRNGs.Uncanonical
is it known what kind of PRNG is implemented in javascript's random()? I'm asking this because I read that the Mersenne Twister is the default PRNG in quite some languagesHygrometric
@kumar_harsh It's implementation-dependent. V8 used to use a (deeply-flawed modification of) MWC, but as far as I know it and Firefox both now use xorshift128+.Perfectionist
H
23

It is not secure at all, and in some cases was so predictable you could rebuild internal state of the PRNG, deduct the seed and thus could use it to track people across websites even if they didn't use cookies, hid behind onion routing etc...

2022 edit since this answer still gets upvotes: use Crypto.getRandomValues if you need a cryptographic RNG in JavaScript

Highstepper answered 13/4, 2011 at 15:53 Comment(3)
Thank you for the link, it's a good example how weak might be a browser's PRNG.Scarborough
The paper I wanted to link is actually the more generic trusteer.com/files/…Ley
Found the new URL for the firt paper and linked it.Ley
G
12

As of March 2013, window.crypto.getRandomValues is an "experimental technology" available since Chrome 11 and Firefox 21 that lets you get cryptographically random values. Also, see getRandomValues from the lastest W3C Web Cryptography API draft.

Description:

If you provide an integer-based TypedArray (i.e. Int8Array, Uint8Array, Int16Array, Uint16Array, Int32Array, or Uint32Array), the function is going fill the array with cryptographically random numbers. The browser is supposed to be using a strong (pseudo) random number generator. The method throws the QuotaExceededError if the requested length is greater than 65536 bytes.

Example:

var array = new Uint32Array(10);
window.crypto.getRandomValues(array);

console.log("Your lucky numbers:");
for (var i = 0; i < array.length; i++) {
    console.log(array[i]);
}

Also, an answer to How random is JavaScript's Math.random? refers to Temporary user tracking in major browsers and Cross-domain information leakage and attacks from 2008 which discusses how the JavaScript Math.random() function leaks information.

Update: For current browser support status, check out the Modern.IE Web Crypto API section, which also links to the Chrome, Firefox, and Safari bug reports.

Gush answered 28/3, 2013 at 14:12 Comment(1)
Current link for the status of the Web Crypto API can be found here: developer.microsoft.com/en-us/microsoft-edge/platform/status/…Husch
E
5

Because you cannot know the exact implementation of the browser (except for closed user groups like for your business intranet) I would generally consider the RNG weak.

Even if you can identify the browser you don't know if the browser itself or any other browser's agent ID is manipulated. If you can you should generate the number on the server.

Even if you include a good PRNG in your JavaScript your server cannot know whether the request from the client originates from an unmodified script. If the number goes into your database and/or is used as a cryptographic tool it is no good idea to trust the data from the client at all. That is true not only for validity (You do validate all data coming from the client, don't you?) but also for general properties like randomness.

Encasement answered 13/4, 2011 at 15:42 Comment(0)
K
0

Here is my proposed solution in Typescript:

/**
 * This method returns a random number between 0 and 1 (Compatible with Math.random())
 * // Compliant for security-sensitive use cases
 * @returns Random number between 0 and 1.
 */
export const randomNumber = (): number => {
  // RandomBytes generates 4 random bytes, which are then read as a 32-bit unsigned integer in little endian.
  // The max value of a 32bit unsigned int is 0xFFFFFFFF (or 4,294,967,295 in decimal).
  // By dividing the randomly generated 32bit int by its max value you get a value between 0 and 1.
  // eslint-disable-next-line unicorn/number-literal-case

  return randomBytes(4).readUInt32LE(0) / 0xffffffff;
};
Kazimir answered 18/7, 2023 at 11:20 Comment(0)
H
-1

If you are looking for a custom random number generator. Which also passes cryptography check.. Something simple as below is enough.

function numberGenerator(max){
    let num = (Date.now() +''); 
    num = parseInt(num.at(num.length-1));

    while(num > max){
        num -= max        
    }

    return num;
}

This can return you a random number between 0-9 which is lower than the max you provide in argument. Feel free to modify it, or just call it twice for 2 digits and concat them.

Hallucinate answered 15/6, 2023 at 11:3 Comment(0)
P
-2

Math.random() is not cryptographically secure. Also Veracode will point this occurrence with

CWE-331 (Insufficient Entropy)

We could make use of SecureRandom to implement similar functionality.

new SecureRandom().nextDouble();
Parquetry answered 17/3, 2017 at 11:53 Comment(2)
is SecureRandom() method available in JavaScript?Deplete
The "SecureRandom.nextDouble" seems to be in Java; which is useless to us in JavaScript.Cooley

© 2022 - 2024 — McMap. All rights reserved.