In PHP there are a lot of ways to generate random numbers. The two most common uses are rand() and mt_rand(). These two functions are great if you are trying to get some random numbers for testing an algorithm. However, you should never use them for generating random passwords, salt for use with a hash, or cryptography. The reason you should not use the two functions is simple — they produce predictable output over time.
PHP has a few ways to generate random numbers or bytes, only some are suitable for password generation or cryptography.
In the past a lot of people have relied on openssl_random_pseudo_bytes() to provide secure random bytes that could then be converted to a number if needed. There was a major issue with openssl_random_pseudo_bytes that was fixed in PHP 5.6.12 5.5.28, and 5.4.44 where PHP was calling the wrong function to get good random bytes. It was recently discovered that openssl has a design limitation that causes PHP’s use of openssl_random_pseudo_bytes to be insecure! For more details take a look at this write up on github https://github.com/ramsey/uuid/issues/80#issuecomment-188286637.
This leaves us with two sets of functions. If you have the mcrypt library installed you could use mcrypt_create_iv() as it’s believed to be a secure source of random bytes. If you are on PHP 7 you can call either random_bytes() or random_int() the best thing about random_int is its API is the same as rand and mt_rand so you don’t need to convert bytes to an int in case you wanted an int in the first place. If PHP 7 is not an option and you don’t have mcrypt or if you don’t want bytes and want a random number you should take a look at https://github.com/paragonie/random_compat.
When you generate a password don’t use functions like array_rand(), shuffle(), or str_shuffle() because they are not going to use a secure random number generator. If you want to generate a salt for a password that you are going to hash you should just call password_hash() instead and let PHP generate the salt for you.
Earlier this year we discovered a few issues around the use of randomness in Zend Framework 1 and worked with Zend to resolve them. For some examples of where mt_rand is the wrong function take a look at the changes in zf1 commit 3b045d0.
If at all possible, you should be using the latest stable version of PHP. Security best practices are a constantly moving target, and PHP 7 has baked in solutions to many known issues in older versions of the language. If you are bound to an older version of PHP for “reasons” it’s your responsibility to keep up with issues like this. Make sure you don’t leave critical legacy PHP applications without critical security updates.
Next Steps
Have questions? Let us know in a comment below, or contact our team directly. You can also check out our other posts on software development.