Not all randomness is created equally
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.
Lava lamps are unpredictable! CloudFlare created LavaRand to take advantage of this. It's a system that uses lava lamps as a secondary source of randomness. A video feed captures the wall of lava lamps and creates random numbers from it.
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.
- STEP 1
- STEP 2
- STEP 3
- STEP 4
- STEP 5
- STEP 6
Setting the stage
Let's take a look at the source code of this application and see if we can predict the randomness for the password reset. Click start to begin!
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
- 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:
- The uuid package using anything other than the
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!
You have taken your first step into learning what insecure randomness is, how it works, what the impacts are, and how to create better random numbers! We hope that you will apply this knowledge to make your applications safer. We'd really appreciate it if you could take a minute to rate how valuable this lesson was for you and provide feedback to help us improve! Also, make sure to check out our lessons on other common vulnerabilities.