Password Security &
Hash Algorithms
Passwords and hashes are the foundation of application security. Learn how they work, when to use each algorithm, and how to avoid the mistakes that lead to data breaches.
Passwords: The First Line of Defense
Every application that handles user accounts needs to deal with passwords. And nearly every developer makes the same mistakes: weak password policies, improper storage, and confusion between encoding and hashing. Understanding the fundamentals prevents these mistakes.
What Makes a Password Strong?
A password's strength is measured by its entropy — how unpredictable it is. Entropy depends on two things: length and character set size. A password of 8 lowercase letters has about 268 possible combinations. Add uppercase and numbers, that jumps to 628. Add symbols: 958.
But the real multiplier is length. Each additional character multiplies the search space by the character set size. A 12-character password with all character types has roughly 9512 ≈ 5.4 × 1023 combinations. At a billion guesses per second, that would take about 17 million years to crack by brute force.
Rules for Strong Passwords
- Use at least 12 characters. 16 is better. Each character adds exponential complexity.
- Mix character types. Uppercase, lowercase, numbers, and symbols.
- Never reuse passwords. If one service is breached, attackers try the same credentials everywhere.
- Use randomly generated passwords. Human-created passwords follow predictable patterns. The Password Generator uses the Web Crypto API for truly random results.
- Use a password manager. You can't remember 50 unique random passwords. Let a manager handle it.
Generate a strong password now with the Password Generator. It uses cryptographically secure random number generation — the same API used by password managers.
Hash Functions: One-Way Streets
A hash function takes input of any size and produces a fixed-size output. The same input always produces the same hash. A tiny change in the input produces a completely different hash. And critically, you cannot reverse a hash to get the original input — it's a one-way function.
MD5: Fast but Broken
MD5 produces a 128-bit (32 hex chars) hash. Designed in 1991, it's now cryptographically broken. Researchers have demonstrated practical collision attacks — two different inputs producing the same MD5 hash. An attacker can create a malicious file with the same hash as a legitimate one.
MD5 is still useful for non-security purposes: file integrity checksums, cache keys, and data deduplication. Never use it for anything security-related.
SHA-1: Also Broken
SHA-1 produces a 160-bit hash. In 2017, Google and CWI demonstrated the first practical SHA-1 collision. SHA-1 should not be used for new systems.
SHA-256: Currently Secure
SHA-256 is part of the SHA-2 family and produces a 256-bit hash. It's the current standard for digital signatures, certificate verification, and blockchain. No practical collision attacks are known. It's the recommended hash function for general-purpose use.
// MD5 — only for non-security checksums
hash("file_check") → "d41d8cd98f00b204e9800998ecf8427e"
// SHA-1 — legacy compatibility only
hash("deprecated") → "da39a3ee5e6b4b0d3255bfef95601890afd80709"
// SHA-256 — security-sensitive applications
hash("secure_data") → "e3b0c44298fc1c149afbf4c8996fb924..."
Generate hashes instantly with the Hash Generator. It computes MD5, SHA-1, and SHA-256 — all in your browser.
Password Hashing ≠ General Hash Functions
This is where many developers go wrong. You should not store passwords using SHA-256. General hash functions are designed to be fast. Password hashing should be slow — slow enough that an attacker can't try billions of guesses per second.
Dedicated password hashing algorithms:
- bcrypt — uses a cost factor that controls computational expense. Increase it over time as hardware improves.
- Argon2 — won the Password Hashing Competition in 2015. Resistant to GPU and ASIC attacks. Current best practice for new applications.
- scrypt — memory-hard design makes it expensive to parallelize on GPUs.
// ❌ Wrong — SHA-256 is too fast for password storage
const hash = sha256(password);
db.store({ username, hash });
// ✅ Right — use bcrypt with an appropriate cost factor
const hash = await bcrypt.hash(password, 12);
db.store({ username, hash });
// ✅ Better — use Argon2id for new applications
const hash = await argon2.hash(password, {
type: argon2.argon2id,
memoryCost: 65536,
timeCost: 3,
parallelism: 4,
});
The Hash Generator on this site uses SHA-256 and MD5 — general-purpose hash functions. It's useful for checksums and data verification. It should not be used for password storage. Use bcrypt, Argon2, or scrypt for that.
Salting: Why Every Hash Should Be Unique
Even with a strong algorithm, you need a salt — a random value added to the password before hashing. Without a salt, two users with the same password have the same hash. An attacker can precompute hashes for common passwords (a "rainbow table") and instantly find any user using one.
With a unique salt per user, identical passwords produce different hashes. The attacker must crack each password individually — orders of magnitude more expensive.
UUIDs: Unique Identifiers for Distributed Systems
UUIDs are 128-bit numbers that identify information without a central authority. UUID v4 generates 122 random bits with 6 reserved for version/variant. The format: 550e8400-e29b-41d4-a716-446655440000 (8-4-4-4-12 hex digits).
The collision probability is astronomically low — you'd need ~2.7 × 1018 UUIDs for a 50% chance of collision. At 1 billion per second, that's about 85 years. Use the UUID Generator to create up to 100 UUIDs at once and download them as a text file.
Quick Reference
| Need | Tool |
|---|---|
| Generate a strong password | Password Generator |
| Hash text with MD5, SHA-1, or SHA-256 | Hash Generator |
| Generate unique identifiers | UUID Generator |
| Decode a JWT token | JWT Decoder |
Handling Password Resets Securely
Password reset flows are among the most attacked features in any application. The key principles: reset tokens must be generated with crypto.randomBytes or an equivalent cryptographically secure source — never Math.random. Tokens must be single-use (invalidated immediately after the password is changed) and time-limited (expiring after 15 to 60 minutes). Store only a SHA-256 hash of the token in the database, the same way you store password hashes. If the database is breached, attackers cannot use the hashed tokens to reset passwords without reversing the hash.
Never reveal whether an account exists during login or password reset. The message "If an account with that email exists, we have sent a reset link" prevents attackers from enumerating your user base by checking which emails produce reset emails and which don't. After the user sets a new password, invalidate all existing sessions — this prevents an attacker who gained access from maintaining it after the password change.
Password Policies That Actually Work
NIST's current guidelines (SP 800-63B) recommend a minimum of 8 characters with no required composition rules. Forcing uppercase, lowercase, numbers, and symbols produces passwords like "Password1!" — technically compliant, trivially crackable. The XKCD "correct horse battery staple" approach — four random words — produces more entropy and is easier to remember. Rate limiting login attempts is at least as important as password complexity. A weak password that can only be tried five times before a 15-minute lockout is more secure in practice than a strong password an attacker can attempt 10,000 times per second. Combine slow hashing (bcrypt or Argon2) with rate limiting for defense in depth.