Password Hashing Done Right: bcrypt, Argon2 & Security

Why regular hashing is wrong for passwords and how to properly secure user credentials.

securitypasswordsbest-practices

Password Hashing

Regular hash functions (SHA-256, etc.) are NOT suitable for passwords. Here's why and what to use instead.

Why SHA-256 is Wrong for Passwords

// ❌ WRONG: Raw SHA-256
const hash = crypto.createHash('sha256')
.update(password)
.digest('hex');

// Problems:
// 1. Too fast - attackers can try billions/second
// 2. No salt - rainbow table attacks
// 3. Identical passwords have identical hashes

The Right Way: bcrypt

import bcrypt from 'bcrypt';

// Hashing a password
const saltRounds = 12;
const hash = await bcrypt.hash(password, saltRounds);
// $2b$12$LQv3c1yqBWVHxkd0LHAkCOYz6TtxMQJqhN8/X4.aAfnvKY5P8m3K.

// Verifying a password
const isMatch = await bcrypt.compare(password, hash);

Even Better: Argon2

import argon2 from 'argon2';

// Hashing
const hash = await argon2.hash(password, {
type: argon2.argon2id, // Recommended variant
memoryCost: 65536, // 64 MB
timeCost: 3, // Iterations
parallelism: 4 // Threads
});

// Verifying
const isMatch = await argon2.verify(hash, password);

Comparison

FeatureSHA-256bcryptArgon2
PurposeGeneralPasswordsPasswords
SpeedFastSlowSlow
SaltManualBuilt-inBuilt-in
Memory-hard
GPU-resistantSomewhat
Recommended✅✅

Best Practices

  • Never store plaintext passwords
  • Use Argon2id or bcrypt
  • Use a work factor that takes ~250ms
  • Increase work factor over time
  • Re-hash on login when upgrading
  • Implement rate limiting
  • Use secure password requirements

Frequently Asked Questions

Common questions about this topic

bcrypt is intentionally slow (configurable work factor) and includes automatic salting. SHA-256 is designed to be fast - attackers can try billions of guesses per second. bcrypt's slowness is a feature: it makes brute force attacks impractical while remaining acceptable for legitimate logins.

The work factor controls how computationally expensive the hash is. Higher values = slower hashing = more secure but slower logins. Target ~250ms per hash. Increase the work factor over time as hardware gets faster. bcrypt uses 2^cost iterations.

Argon2 (specifically Argon2id) is the current recommendation - it won the Password Hashing Competition and is memory-hard (resists GPU attacks). bcrypt is still secure and more widely supported. Both are excellent choices. Avoid PBKDF2 unless required for compliance.