Security Tip: Don't Generate Your Own Passwords!

[Tip #113] "Don't Roll Your Own Crypto" applies to password generators too! It's way too easy to unknowingly lower your entropy by trying to be clever... 😱

Security Tip: Don't Generate Your Own Passwords!

Following on from last week's Security Tip: Don't Use phpinfo()!, we have another example of vulnerable code that I came across during a security audit.

Take a look:

function generatePassword($length = 9): string
{
    $characters = str_split('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ');

    $password = '';
    $password .= $characters[rand(10, 35)];
    $password .= $characters[rand(36, 61)];
    $password .= $characters[rand(0, 9)];

    while (strlen($password) < $length) {
        $password .= $characters[array_rand($characters)];
    }

    return $password;
}

There are a number of small problems here that combine together into two main issues:

Terrible Entropy!

  1. The function defaults to 9 character passwords, which is well short of the recommended 15 characters by NIST.
  2. There is a limited character set with only 62 possible characters: 0-9, a-z, and A-Z. Well short of the 95 standard ASCII characters that could be used.
  3. The format is predictable: lower-case character, upper-case character, digit, then 6 random characters (([a-z][A-Z][0-9][0-9a-zA-Z]{6}). This is identifiable given a large enough set.

Combine all of these, and the resulting entropy is incredibly limited:

logâ‚‚( 26 [lower] x 26 [upper] x 10 [digit] x (26 + 26 + 10)^6) => 48 bits of entropy

Compare that to the entropy of a 15 character password using a 95 character set:

logâ‚‚( 95 ^ 15 ) => 96 bits of entropy

Yeah... it's bad.

🤓
"Entropy" is basically just a fancy word for how random a password is, based on how many possible options there are.

Insecure Randomness!

Not only does this password generator have terrible entropy, but it's also using PHP's rand() and array_rand() functions - which do not generate cryptographically secure random values!

Instead, they generate a set of known outputs from a limited set of seed values, which makes them predictable under the right conditions. Therefore, it is theoretically possible that an attacker could generate the list of all possible passwords this generator could produce - making brute-force or cracking attacks significantly easier.

What Is The Solution?

If you have a password generator in your code, go delete it.

I'm being serious here, unless you're a cryptography nerd, go delete your custom password generator!

It's way too easy to make a mistake trying to roll your own crypto, and end up with a weak password generator that produces terrible passwords. Instead, you want to use an existing password generator that's been properly tested and reviewed.

I'd suggest starting with Laravel's Str::password() helper - it's been in the framework since version 10 and has some basic configuration options for length and toggling character sets.

Alternatively, if you need something with more power, check out Random::password() from my valorin/random package. It gives you full control over the exact characters included, and I've had a couple of crypto-nerds review the code to make sure it's safe.


If you found this security tip useful, subscribe to get weekly Security Tips straight to your inbox. Upgrade to a premium subscription for exclusive monthly In Depth articles, or drop a coin in the tip jar to show your support.

When was the last time you had a penetration test? Book a Laravel Security Audit and Penetration Test, or a budget-friendly Security Review!

You can also connect with me on Bluesky, or other socials, and check out Practical Laravel Security, my interactive course designed to boost your Laravel security skills.

OSZAR »