Summary of what I know about this subject. Here's what I've been able to find, in my own research:
All browsers provide
Math.random()as a library call to generate pseudorandom numbers. Unfortunately, it does not provide crypto-quality random numbers and fails the requirement above. On the browsers I've seen,
Math.random()uses a non-cryptographic PRNG, and its internal state is shared across multiple sites. Therefore, evil.com can call
Math.random()a bunch of times, recover the internal state of the PRNG, and then infer what random numbers a.com got when it called
Math.random(). Also, it uses a non-cryptographic-quality PRNG, so if a.com generates a random key and a random IV using
Math.random()and then publishes the IV, it might be possible to infer the PRNG's internal state (from the IV) and then recover the key. So,
Math.random()is right out.
However, it appears to have a hefty limitation: if I'm reading the paper correctly, it takes 10-40 seconds of user interaction with your site before the pseudorandom number gets adequately seeded. Moreover, each site has to start over from scratch: if a.com includes the SJCL library, then it looks like a.com's script has to wait for the user to interact with the a.com site for 10-40 seconds (typically) before a.com can generate crypto-quality random numbers. This is a pretty significant limitation.
Here's their paper:
The bottom line is that I don't know of any reasonable solution; the options I found all seem pretty problematic. However, it has been several years since those papers and essays were written, and I know that web technology can change rapidly. Does anyone know of any good solution to this problem?