When working with security and especially cryptography one often needs to generate a sequence of bytes which should be uniformly random. This is the case when creating a nonce for OAuth, and many other applications.
This problem is often mistaken for the problem of generating a random string. However, a random sequence of bytes is not a string. But can be represented as a string. And often this is exactly what you want, hence the name of this post.
If I use Google to search for "js random string", then I will get many suggestions on how to generate a random string in JavaScript. However, they are either not cryptographically secure or they rely on Node.js. I will ignore the Node.js versions as they seems to fine.
So what is wrong with the many insecure solutions:
- They use Math.random() which is not cryptographically secure.
- They tend to use a reduced alphabet of only alphanumeric characters
One example of the insecure random is this from this
SO:
1
2
3
4
5
6
7
8
9
10
| function makeid()
{
var text = "";
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for( var i=0; i < 5; i++ )
text += possible.charAt(Math.floor(Math.random() * possible.length));
return text;
}
|
A better approach is to use the window.crypto.getRandomValues method from the WebCrypto API, which states that the Browser is supposed to use a strong strong (pseudo) random number generator. And then encode the result as Base64. Notice that this method will generate a random sequence of
numberOfBytes bytes and then base64 encode these. This will generally result in a string of more than numberOfBytes characters.
1
2
3
4
5
| function randomString (numberOfBytes) {
var array = new Uint8Array(length);
window.crypto.getRandomValues(array);
return btoa(String.fromCharCode.apply(null, array));
}
|
This approach is not foolproof either. As mentioned in this
SO comment you might not want to trust the client to generate randomness. However, there are situations where you want to, so the call is up to you.