Brute Force Password Attacks — How They Work and How to Defend Against Them
Brute force attacks try every possible password combination. Learn how attackers estimate crack times, why GPU speed matters, how bcrypt/Argon2 slow attacks, and what password...
A brute force attack tries every possible password until it finds the right one. The only defense is entropy (randomness) and slow hashing — not complexity rules.
Generate high-entropy passwords with the Password Generator.
How brute force works
Attacker gets your password hash from a breached database.
They run hashing software against millions/billions of candidates per second.
When hash(candidate) == stored_hash → password found.
Types of brute force:
1. Pure brute force: try all combinations (a, b, ..., aa, ab, ...)
2. Dictionary attack: try common words and variations
3. Rule-based: apply transforms (password → P@ssw0rd, p4ssword, ...)
4. Rainbow tables: precomputed hash→password lookup (defeated by salting)
Cracking speeds (2024 hardware)
Algorithm Hashes/second (RTX 4090)
─────────────────────────────────────────────
MD5 68,000,000,000 (68 billion/sec)
SHA-1 25,000,000,000 (25 billion/sec)
SHA-256 12,000,000,000 (12 billion/sec)
bcrypt (cost=10) 184,000 (184 thousand/sec)
bcrypt (cost=12) 46,000 (46 thousand/sec)
Argon2id (default) 1,000 (1 thousand/sec)
scrypt (N=32768) 1,500 (1.5 thousand/sec)
bcrypt is 65,000× slower than SHA-256 per guess. This is by design.
Crack time estimates
function crackTime(passwordSpace, hashesPerSecond) {
const averageGuesses = passwordSpace / 2; // Find it halfway on average
const seconds = averageGuesses / hashesPerSecond;
if (seconds < 60) return `${seconds.toFixed(0)} seconds`;
if (seconds < 3600) return `${(seconds/60).toFixed(0)} minutes`;
if (seconds < 86400) return `${(seconds/3600).toFixed(1)} hours`;
if (seconds < 31536000) return `${(seconds/86400).toFixed(0)} days`;
return `${(seconds/31536000).toFixed(0)} years`;
}
// Password space = charset^length
const lower8 = 26**8; // 208 billion
const mixed12 = 95**12; // 540 quadrillion
const diceware5 = 7776**5; // 28 octillion
// Against SHA-256 (12B/sec):
crackTime(lower8, 12e9); // "9 seconds"
crackTime(mixed12, 12e9); // "1,424 years"
crackTime(diceware5, 12e9); // "74 billion years"
// Against bcrypt cost=12 (46K/sec):
crackTime(lower8, 46000); // "2.6 days"
crackTime(mixed12, 46000); // "372 million years"
Why bcrypt defeats GPU attacks
GPU advantage: parallel computation
MD5/SHA: massively parallel on GPU (thousands of concurrent hash operations)
bcrypt: memory-hard, sequential operations → GPU offers minimal speedup
bcrypt internal loop: 2^cost iterations of Blowfish key schedule
cost=10: 2^10 = 1024 iterations
cost=12: 2^12 = 4096 iterations
cost=14: 2^14 = 16384 iterations (login ~300ms)
GPU can run many bcrypt instances in parallel,
but each instance takes the same wall-clock time.
Result: bcrypt at cost=12 ≈ 46,000/sec even on RTX 4090
vs SHA-256: 12,000,000,000/sec
260,000× slower per guess = effectively impossible for high-entropy passwords
Entropy thresholds
At bcrypt cost=12 (46,000 hashes/sec):
Entropy Keyspace Crack time
─────────────────────────────────────────
40 bits 1.1 trillion 7 hours
50 bits 1.1 quadrillion 290 days
60 bits 1.2 quintillion 810 years
70 bits 1.2 sextillion 830,000 years
80 bits 1.2 septillion 849 million years
Recommendation: 60+ bits of entropy minimum for bcrypt-protected passwords
5-word diceware: 64.6 bits ✓
Random 10-char (mixed): 65.7 bits ✓
Random 12-char (lowercase): 56.4 bits ✗ (borderline)
Dictionary attack defense
# Attackers try common passwords first:
# "password", "123456", "qwerty", "letmein" → cracked in <1 second regardless of hash
# Defense: reject common passwords at registration
import requests
def is_common_password(password: str) -> bool:
"""Check against Have I Been Pwned API (k-anonymity model)."""
import hashlib
sha1 = hashlib.sha1(password.encode()).hexdigest().upper()
prefix = sha1[:5]
suffix = sha1[5:]
response = requests.get(f'https://api.pwnedpasswords.com/range/{prefix}')
for line in response.text.splitlines():
hash_suffix, count = line.split(':')
if hash_suffix == suffix:
return True # Found in breach database
return False
# At registration:
if is_common_password(password):
raise ValueError("This password has appeared in data breaches. Choose another.")
Rate limiting defense (online attacks)
Brute force against a live login form (online attack) is slower than offline hash cracking:
// Express: rate limit login attempts
import rateLimit from 'express-rate-limit'; // npm install express-rate-limit
const loginLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 10, // 10 attempts per window per IP
skipSuccessfulRequests: true,
message: { error: 'Too many login attempts. Try again in 15 minutes.' },
});
app.post('/login', loginLimiter, async (req, res) => {
// ... authentication logic
});
// Per-account lockout (prevents distributed attacks):
async function checkAccountLockout(email) {
const attempts = await redis.incr(`login:fail:${email}`);
if (attempts === 1) await redis.expire(`login:fail:${email}`, 900); // 15min TTL
if (attempts > 5) {
throw new Error('Account locked due to too many failed attempts.');
}
}
Credential stuffing (not pure brute force)
Credential stuffing ≠ brute force
Attacker uses known email+password pairs from OTHER breaches.
Defense: different password on every site.
Tools defenders use:
- Have I Been Pwned API: check if email/password appears in breaches
- Device fingerprinting: detect bot-like login patterns
- CAPTCHA on failed login threshold
- Magic link / passkey (no password = no credential stuffing)
Related tools
- Password Generator — generate high-entropy passwords
- Diceware Passphrase Guide — entropy-optimal passwords
- Hash Generator — understand password hashing
Related posts
- How Secure Is My Password? Entropy, Crack Times, and What Actually Matters — Password security measured in bits of entropy, real hashcat benchmarks on RTX 40…
- Diceware Passphrases — Stronger and More Memorable Than Passwords — Diceware generates memorable passphrases by rolling dice to select words from a …
- Generate Strong Password — What Makes a Password Uncrackable — A strong password has high entropy — generated randomly from a large character s…
- bcrypt Password Hashing — Why You Should Use bcrypt and How to Implement It — bcrypt is the standard password hashing algorithm for web applications. Learn wh…
Related tool
Generate strong random passwords with configurable length, character classes, and exclusions. Real entropy meter, crack-time estimate, bulk mode.
Written by Mian Ali Khalid. Part of the Encoding & Crypto pillar.