Security Tip: Cryptographically Secure Randomness
[Tip#19] Because all randomness should be cryptographically secure.
Computers are terrible at generating randomness. Give a computer the exact same inputs and it will produce the exact same outputs. If you can figure out the starting point (“seed”), you can figure out the values. This is a huge problem when you consider that cryptography depends on generating unpredictable random keys. If you can predict the key used to encrypt something, you can decrypt it.
So how do computers get around this? Computers use entropy to help generate randomness, which can be collected from all sorts of sources, including user activity and general noise detected within the hardware. Cloudflare have even taken it a step further, and have an entire wall filled with Lava Lamps which generates a significant amount of entropy for use in cryptography.
Although it’s not truly random, it’s good enough to be considered “cryptographically secure”.
This brings us to PHP and Laravel. When we’re generating random values in PHP and Laravel, we always want to be using cryptographically secure randomness - which is actually pretty simple. You just need to use the right methods.
Secure Functions
PHP 7 & 8 includes two cryptographically secure methods by default, which you should always use when you need a random value.
random_int()
generates random numbers:
$number = random_int($min, $max);
random_bytes()
generates random bytes, which you can use to generate random strings. Laravel includes the Str::random()
helper, which uses random_bytes()
internally to generate friendly random strings for you:
use Illuminate\Support\Str;
$random = Str::random($length);
My Random Package
Another option, or if you need more complex randomness than basic numbers and strings, I have released a Random package, which provides a bunch of helper functions for common randomness needs.
You can find it on GitHub: https://github.com/valorin/random
And check out the announcement post for all the details: Introducing Random.
Unsafe Functions
The following functions are not cryptographically secure and should not be used except when securely is not a concern:
md5(time())
md5(microtime())
md5($model->id . time())
md5(rand(...).time())
sha1(time())
rand($min, $max)
mt_rand($min, $max)
tempnam(...)
md5(rand($min, $max))
base64_encode(...)
base64_encode(rand(...))
md5(base64_encode(time()))
str_shuffle(...)
shuffle()
array_rand()
All of these can be guessed if the attacker has enough time and motivation, and the time-based ones are absolutely trivial.
md5()
gets used for something that’s supposed to be secure.Note aboutshuffle()
andarray_rand()
: they don’t use a cryptographically secure random number, so they aren’t safe for any secure purposes or anything that requires true randomness. There is the possibility that their order can be predicted, and if this is a concern, you need to use a cryptographically secure shuffling method.
TheArr::shuffle()
in Laravel 10 usesshuffle()
internally, which makes it unsuitable for any secure application. Laravel 11 has been updated to use a secure shuffle, and is safe to use.
Found this security tip helpful? Don't forget to subscribe to receive new Security Tips each week, and upgrade to a premium subscription to receive monthly In Depth articles, or toss a coin in the tip jar.
Reach out if you're looking for a Laravel Security Audit and Penetration Test or a budget-friendly Security Review, and find me on the various socials through Pinkary. Finally, don't forget to check out Practical Laravel Security, my interactive security course.