Insecure Randomness
Not all randomness is created equally
JavaScript
What is insecure randomness?
Insecure randomness refers to random numbers or data that do not have enough entropy, or randomness, to be considered truly random. This occurs when a function that is expected to return a random value actually has a predictable output, allowing an attacker to compromise security.
Computers are not able to produce truly random values due to their deterministic nature, so Pseudo-Random Number Generators are used instead. The predictability of the output of these generators varies significantly.
This lack of true randomness can make these numbers vulnerable to being exploited by attackers for various purposes, such as cracking encryption or predicting the outcomes of games of chance. It is important to use secure, high-quality sources of randomness to ensure the security and integrity of sensitive information and systems.
About this lesson
During this lesson, we'll learn what about randomness and what we mean by insecure randomness. We’ll look at how an attacker can exploit the weakness in "random" generation to attack a system. After that, we’ll learn how to create a something truly random and fix our vulnerability.
Sam the hacker decides on his next target, his local doctor's office. They have a web application which allows patients to view their medical records. With a bit of light reconnaissance, Sam quickly figures out that this application is actually a piece of open-source software called "My Super Secure Medical Records" or just MSSMR for short. Let's see the attack in action.
The vulnerable code in the application is reiterated below:
In this case, a token that needs to be random is being generated in a way that is completely predictable. The attacker was able to recreate their own tokens in order to take full control of any account. While this is quite an obvious example, there are plenty of other less-obvious ways that tokens can be generated insecurely, and it all comes down to pseudo-random number generators.
What is a pseudo-random number generator (PRNG)?
Unfortunately, it is impossible for a computer to produce a truly random number because computers are deterministic. Instead, when we need to generate a random number we use functions that approximate randomness as well as is possible with a deterministic machine. These functions are called PRNGs.
There are two types of PRNGs, statistical and cryptographic. Statistical PRNGs are highly predictable and are therefore not suitable for functions that rely on randomness for security purposes. Cryptographic PRNGs make prediction infeasible and are therefore appropriate for use in a security context.
As a rule of thumb, a PRNG algorithm should only be used in a security context if it is advertised to be cryptographically secure.
What is the impact of insecure randomness?
The impact of a vulnerability resulting from insecure randomness is dependent on the context that the randomness is being used in. For a typical application, the main use for randomness is to generate secure tokens - in which case, the impact is quite severe: An attacker is able to generate their own tokens to access sensitive data or perform sensitive functionality that would otherwise be inaccessible to them.
There is no definitive answer to mitigating insecure randomness. Some possible methods include using a more reliable random number generator, mixing in entropy from other sources, and/or using a cryptographic hash function to combine multiple sources of entropy.
For most applications, the only time cryptographically secure numbers need to be generated would be when designing authentication processes. In this case, using a popular, well-respected framework that comes with these processes already written is a huge leg-up. Similarly, if you just need to generate cryptographically secure tokens, find a good library that is designed to do just that. Don't reinvent the wheel.
If you do need to generate your own tokens, ensure that the underlying PRNG is cryptographically secure. The documentation for all reputable random number generators will have this information freely available.
What to use and what not to use
Here are some recommendations:
- The uuid package, specifically the
v4()
function - If you need to generate a cryptographically secure number within a range, use the random-number-csprng package
- The built-in crypto package called randomBytes()
What isn't recommended are:
Math.random()
- The uuid package using anything other than the
v4()
function
For the uuid package, the previous versions are not recommended due to the possibility of predictability. For example, uuid v1 uses time and the user's MAC address as part of the creation process. Someone could potentially use these two inputs to predict the output.
For v4, there are 5.3 x 10^36 unique UUIDs!
A word of warning - randomness issues can also arise in how you transform the data after the seeds have been generated. As a rule of thumb, it's best to use the data in a format that is as raw as possible.
Mitigating the vulnerable code snippet
In this case, the easiest way to mitigate the vulnerability would be to just edit the generateForgotPasswordToken()
function to use a cryptographically secure UUID, like this:
Test your knowledge!
Keep learning
- Read more about insecure randomness from the OWASP website
- Keep learning with insecure hash
- A good JS package is the random number CSPRNG npm package
- And there is also the UUID npm package