DEV Community

Snappy Tools
Snappy Tools

Posted on

What Makes a Password Actually Secure? A Developer's Guide

Everyone knows passwords should be "strong". But what does that actually mean in practice? This guide explains the math behind password security, what makes a password hard to crack, and how to generate passwords that meet modern security requirements.

The core metric: entropy

Password strength is measured in bits of entropy. Entropy quantifies how hard a password is to guess by brute force — specifically, how many guesses an attacker must make in the worst case.

The formula:

entropy = log2(character_set_size ^ password_length)
         = password_length × log2(character_set_size)
Enter fullscreen mode Exit fullscreen mode

For a 12-character password using only lowercase letters (26 characters):

entropy = 12 × log2(26) = 12 × 4.7 = 56.5 bits
Enter fullscreen mode Exit fullscreen mode

For a 12-character password using lowercase + uppercase + digits + symbols (94 characters):

entropy = 12 × log2(94) = 12 × 6.55 = 78.6 bits
Enter fullscreen mode Exit fullscreen mode

Modern recommendations (NIST SP 800-63B) suggest 80+ bits of entropy for sensitive accounts.

How long should passwords be?

Length matters more than complexity. A 16-character password using only lowercase letters has 75 bits of entropy — stronger than a 12-character mixed-case+symbols password with 78 bits? Almost — and the longer one is much easier to type.

Length Charset Entropy Cracking time (1T guesses/sec)
8 a–z (26) 37.6 bits ~4 minutes
8 Full ASCII (94) 52.4 bits ~50 days
12 Full ASCII (94) 78.6 bits ~14,000 years
16 Full ASCII (94) 104.8 bits ~900 million years
20 a–z only (26) 94 bits ~700,000 years

Modern GPUs can test billions of hashes per second — but against offline attacks on bcrypt or Argon2 hashes, the rate drops to thousands per second. Against online login attempts (with rate limiting), 10–100 guesses per second is typical.

The practical takeaway: 12+ characters with a mixed charset puts you safely beyond reach of any realistic attack. 16+ characters is future-proof.

Character sets: what each adds

Adding character classes increases the pool size, increasing entropy per character:

  • Lowercase a–z: 26 characters → 4.7 bits per character
  • + Uppercase A–Z: 52 characters → 5.7 bits per character (+1 bit)
  • + Digits 0–9: 62 characters → 5.95 bits per character (+0.25 bits)
  • + Symbols: 94 characters → 6.55 bits per character (+0.6 bits)

Each addition gives diminishing marginal returns. Length scales linearly with entropy; character set expansion is logarithmic. Doubling password length from 8 to 16 characters roughly doubles entropy. Switching from lowercase-only to full ASCII only adds ~40%.

Common mistakes

Predictable patterns: P@ssword1 passes most "strong password" checkers (uppercase, symbol, digit) but has very low real entropy because it follows a predictable human pattern. Dictionary attacks include common substitutions.

Reusing passwords: the most common real-world attack is credential stuffing — attackers use usernames and passwords from one breached site to try other sites. A strong password that is reused across 20 sites provides weak protection.

Short passwords with high complexity requirements: a 8-character password with uppercase, digit, and symbol required has ~52 bits of entropy — crackable offline in weeks with modern hardware.

Security questions: "mother's maiden name" is not a second factor; it is a weak password. Treat security question answers as passwords: generate a random string and store it in a password manager.

NIST's current recommendations

NIST SP 800-63B (2024 update) shifted guidance significantly:

  • Minimum 8 characters — allow long passwords (64+ characters)
  • Do not require complexity rules (uppercase/digit/symbol requirements cause predictable patterns)
  • Check against breached password lists (use the Have I Been Pwned API)
  • Do not force periodic password changes unless there is evidence of compromise
  • Allow paste in password fields — prevents password manager friction

For applications, NIST recommends checking submitted passwords against known-compromised lists rather than enforcing arbitrary complexity rules.

Generating secure passwords

Truly random passwords are generated by a CSPRNG (cryptographically secure pseudo-random number generator):

Python:

import secrets, string
charset = string.ascii_letters + string.digits + string.punctuation
password = ''.join(secrets.choice(charset) for _ in range(16))
Enter fullscreen mode Exit fullscreen mode

Node.js:

const crypto = require('crypto');
const charset = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*';
const password = Array.from(crypto.randomBytes(16))
  .map(b => charset[b % charset.length])
  .join('');
Enter fullscreen mode Exit fullscreen mode

Go:

import (
    "crypto/rand"
    "math/big"
)

func generatePassword(length int, charset string) string {
    result := make([]byte, length)
    for i := range result {
        n, _ := rand.Int(rand.Reader, big.NewInt(int64(len(charset))))
        result[i] = charset[n.Int64()]
    }
    return string(result)
}
Enter fullscreen mode Exit fullscreen mode

The key point: use crypto/rand, secrets, or crypto.randomBytes — not Math.random(), random.random(), or rand.Intn() (the non-crypto versions). Predictable randomness in password generation is a real vulnerability.

Quick generation

For development credentials, test accounts, or one-off needs, the Password Generator on SnappyTools generates cryptographically random passwords with configurable length and character sets. Everything runs in your browser — nothing is transmitted.


Need a strong password right now? Generate one instantly — adjustable length, charset, and bulk generation for seeding test databases.

Top comments (0)