← All Posts

How to Generate a Secure Random Password (Best Practices)

Published on February 10, 2026

Passwords remain the primary authentication mechanism for the vast majority of online services. Despite the rise of passkeys, biometrics, and multi-factor authentication, a strong password is still the foundation of account security. Yet most people use weak, predictable passwords that can be cracked in seconds. In this guide, we will explain the mathematics behind password strength, demonstrate why common approaches to password generation are insecure, and show you how to generate truly random, cryptographically secure passwords.

Password Entropy Explained

Entropy is the mathematical measure of randomness in a password. It is expressed in bits and calculated using the formula: entropy = log2(N^L), where N is the number of possible characters (the character set size) and L is the password length. Equivalently, entropy = L * log2(N).

Here is what this means in practice:

  • A 8-character password using only lowercase letters (26 characters): 8 * log2(26) = 37.6 bits of entropy.
  • A 8-character password using lowercase + uppercase + digits (62 characters): 8 * log2(62) = 47.6 bits of entropy.
  • A 12-character password using lowercase + uppercase + digits + symbols (95 characters): 12 * log2(95) = 78.8 bits of entropy.
  • A 16-character password using the full 95-character printable ASCII set: 16 * log2(95) = 105.1 bits of entropy.

Each additional bit of entropy doubles the number of possible passwords an attacker must try. A password with 40 bits of entropy has approximately 1 trillion possible combinations. A password with 80 bits has approximately 1.2 septillion combinations. At 128 bits, the number of possibilities exceeds the number of atoms in the observable universe.

How Much Entropy Is Enough?

The answer depends on the threat model. For online attacks (where the attacker tries passwords against a login form), rate limiting and account lockout policies mean that even 40 bits of entropy is often sufficient. An attacker limited to 100 attempts before lockout cannot crack a 40-bit password through brute force.

For offline attacks (where the attacker has obtained a database of hashed passwords), the requirements are much higher. A modern GPU can compute billions of hashes per second. Against a fast hash like MD5 or SHA-1, a password with 50 bits of entropy can be cracked in minutes. Against a slow hash like bcrypt or Argon2 (which are designed for password storage), the same entropy level provides years of resistance.

The current recommendation from security experts is a minimum of 80 bits of entropy for general use and 128 bits for high-security applications. A 16-character password using the full printable ASCII set comfortably exceeds this threshold.

Why Math.random() Is Insecure

Many password generators found online or written by developers use JavaScript's Math.random() to generate random characters. This is a critical security flaw. Math.random() is a pseudorandom number generator (PRNG) designed for statistical simulations and games, not for security.

Here is why it is unsuitable for password generation:

1. Predictable State

Math.random() uses an internal state that is updated with each call. In most JavaScript engines, this state is seeded from a low-entropy source (often the current timestamp). If an attacker knows or can guess when the password was generated, they can narrow down the possible passwords dramatically. In V8 (Chrome and Node.js), the PRNG uses the xorshift128+ algorithm with a 128-bit state. Knowing just a few outputs allows an attacker to reconstruct the full state and predict all future outputs.

2. No Cryptographic Guarantees

A cryptographically secure PRNG (CSPRNG) guarantees that knowing any number of outputs does not help an attacker predict future outputs. Math.random() provides no such guarantee. It is designed for speed and statistical uniformity, not for resistance to adversarial prediction.

3. Insufficient Entropy

The internal state of Math.random() is finite and relatively small. Even though the output appears random, the total number of possible sequences is limited by the state size. This means that the actual entropy of passwords generated with Math.random() may be significantly lower than the theoretical entropy based on the character set and length.

The Secure Alternative: crypto.getRandomValues()

The Web Crypto API provides crypto.getRandomValues(), which is the correct way to generate random values for security-sensitive purposes in JavaScript. This function uses the operating system's cryptographic random number generator, which draws entropy from hardware events (keyboard timing, mouse movements, disk I/O, thermal noise).

Here is a comparison of the two approaches:

Insecure (Math.random)

// DO NOT USE THIS FOR PASSWORDS
function insecurePassword(length) {
    const chars = "abcdefghijklmnopqrstuvwxyz"
        + "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        + "0123456789!@#$%^&*";
    let password = "";
    for (let i = 0; i < length; i++) {
        password += chars[Math.floor(
            Math.random() * chars.length
        )];
    }
    return password;
}

Secure (crypto.getRandomValues)

function securePassword(length) {
    const chars = "abcdefghijklmnopqrstuvwxyz"
        + "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        + "0123456789!@#$%^&*";
    const randomValues = new Uint32Array(length);
    crypto.getRandomValues(randomValues);
    let password = "";
    for (let i = 0; i < length; i++) {
        password += chars[randomValues[i] % chars.length];
    }
    return password;
}

The code looks almost identical, but the security properties are fundamentally different. The secure version uses the OS-provided CSPRNG, which is resistant to prediction even if the attacker knows the algorithm and has observed previous outputs.

In Node.js, the equivalent is crypto.randomBytes() from the built-in crypto module, which also uses the OS CSPRNG.

Character Set Impact on Strength

The character set you use for password generation has a direct impact on entropy per character. Here is a breakdown:

  • Digits only (0-9) — 10 characters, 3.32 bits per character. A 16-digit PIN has 53 bits of entropy. Suitable only for numeric-only inputs.
  • Lowercase letters (a-z) — 26 characters, 4.70 bits per character. A 16-character password has 75 bits. Acceptable but not ideal.
  • Lowercase + uppercase (a-z, A-Z) — 52 characters, 5.70 bits per character. A 16-character password has 91 bits. Good for systems that do not allow symbols.
  • Alphanumeric (a-z, A-Z, 0-9) — 62 characters, 5.95 bits per character. A 16-character password has 95 bits. A strong default choice.
  • Full printable ASCII — 95 characters (including symbols like !@#$%^&*()-_=+), 6.57 bits per character. A 16-character password has 105 bits. The strongest option for standard passwords.

The trade-off is usability. Passwords with symbols are harder to type, especially on mobile keyboards. Some websites and applications restrict which characters are allowed. For maximum compatibility, alphanumeric passwords of 20+ characters provide excellent security without symbol-related issues.

Passphrases: An Alternative Approach

Instead of a random string of characters, a passphrase uses randomly selected dictionary words. For example: "correct horse battery staple" (the famous xkcd example). The entropy of a passphrase depends on the dictionary size and the number of words.

Using a dictionary of 7,776 words (the EFF dice word list), each word provides log2(7776) = 12.9 bits of entropy. A 6-word passphrase provides 77 bits of entropy, and an 8-word passphrase provides 103 bits. These are strong enough for most purposes while being significantly easier to memorize than a random string like xK9#mP2$vL7@nQ4.

The critical requirement is that the words must be selected randomly, not chosen by a human. Humans are terrible at being random. If you pick your own words, you will gravitate toward common words, personal associations, and familiar patterns, dramatically reducing the effective entropy.

Password Manager Tips

A password manager is the practical solution to the password problem. It generates, stores, and auto-fills strong unique passwords for every account. Here are best practices for using one effectively:

  • Use a unique password for every account — This is the primary benefit of a password manager. If one service is breached, your other accounts are unaffected.
  • Generate passwords of at least 16 characters — With a password manager handling storage and entry, there is no reason to use short passwords. Longer is always better.
  • Use a strong master password — Your master password protects all other passwords. Use a long passphrase (6+ words) that you can memorize. This is the one password you must remember.
  • Enable two-factor authentication on the password manager — Protect the keys to the kingdom with a second factor, preferably a hardware security key (YubiKey) or TOTP app (not SMS).
  • Keep an encrypted backup — Export your password vault periodically and store the encrypted backup in a separate, secure location. If you lose access to your password manager, you need a recovery path.
  • Audit regularly — Most password managers have a security audit feature that identifies weak, reused, or compromised passwords. Review it quarterly.

Common Password Mistakes

Even security-aware people make these mistakes. Understanding them helps you avoid them:

1. Dictionary Words

Using a single dictionary word (even with letter substitutions like "p@ssw0rd") is extremely weak. Attackers use dictionary attacks that try every word in multiple languages, along with common substitution patterns. The word "p@ssw0rd" has approximately 1 bit of entropy against a dictionary attack because it is in every cracker's word list.

2. Personal Information

Names, birthdays, pet names, addresses, and phone numbers are not random. They can be found on social media, public records, and data broker sites. An attacker targeting you specifically will try these first.

3. Keyboard Patterns

Patterns like "qwerty", "123456", "zxcvbn", and "asdfghjkl" are among the most commonly used passwords. Crackers include all keyboard walk patterns in their initial attacks. The same applies to patterns on the numpad and number row.

4. Simple Transformations

Adding "123" or "!" at the end of a word, capitalizing the first letter, or reversing the string are all predictable transformations that crackers account for. "Password1!" has trivial entropy against a targeted attack despite technically meeting many complexity requirements.

5. Reusing Passwords

This is the single most dangerous practice. When a service is breached (and it is a question of when, not if), attackers try the exposed credentials against every other popular service. If you use the same password for your email and a compromised forum, your email account is now compromised too. This is called credential stuffing and is the most common attack vector for account takeovers.

6. Short Passwords

Even with a perfect character set, a password shorter than 12 characters does not provide enough entropy to resist offline brute-force attacks against modern hardware. Eight-character passwords of any complexity can be cracked in hours using GPU-accelerated tools like Hashcat when the hash function is not sufficiently slow.

Password Strength Checklist

When generating a password, verify that it meets these criteria:

  • At least 16 characters long (20+ is better).
  • Generated using a cryptographically secure random number generator, not chosen by a human.
  • Uses a diverse character set (uppercase, lowercase, digits, and symbols if the service allows them).
  • Unique to this specific account (never reused).
  • Stored in a password manager (not written on a sticky note, not in a plain text file, not in your browser's basic password storage without a master password).
  • Backed by two-factor authentication wherever possible.

Need to extract data from websites?

PulpMiner turns any webpage into structured JSON data. No scraping code needed.

Try PulpMiner Free

No credit card required