← Back to Blog

Password Hashing Best Practices for Developers

Why Password Hashing Matters

Never store passwords in plaintext! If your database is breached:

  • Plaintext: Attackers have all passwords immediately
  • Hashed: Attackers must crack each hash individually

The Problem with Simple Hashing

Using SHA-256 directly on passwords is not secure:

``

password123 → SHA-256 → ef92b778bafe771e89245b89ecbc08a44a4e166c06659911881f383d4473e94f

`

Problems:

  • Rainbow tables: Pre-computed hash databases
  • Speed: Modern GPUs can compute billions of hashes per second
  • No salt: Same password = same hash for all users
  • The Solution: Salting

    A salt is random data added to each password before hashing:

    `

    password123 + randomsalt123 → hash

    password123 + differentSalt → completely different hash

    `

    Benefits:

    • Defeats rainbow tables
    • Same password produces different hashes for different users
    • Attacker must crack each hash individually

    Modern Password Hashing Algorithms

    bcrypt

    `

    $2b$12$LQv3c1yqBwEHxPzVu3Nfx.6YH2cR/uvgNmNpNkw7J8fQr.l2Cm/Oy

    `

    • Built-in salt
    • Configurable work factor
    • Widely supported
    • Recommended for most applications

    Argon2

    • Winner of Password Hashing Competition (2015)
    • Configurable memory, time, and parallelism
    • Most secure option available
    • Variants: Argon2d, Argon2i, Argon2id

    scrypt

    • Memory-hard function
    • Resists GPU attacks
    • Good alternative to bcrypt

    Implementation Guidelines

    DO:

  • Use bcrypt, Argon2, or scrypt
  • Use unique salt per password (automatic with these algorithms)
  • Use appropriate work factors
  • Hash on the server, not client
  • Use constant-time comparison
  • DON'T:

  • Use MD5, SHA-1, or plain SHA-256
  • Create your own hashing scheme
  • Use the same salt for all passwords
  • Store salt separately from hash (not necessary)
  • Use fast hash functions
  • Work Factor Recommendations

    The work factor (cost) should make hashing take ~100-500ms:

    bcrypt:

    `javascript

    // Cost factor of 12 is a good starting point

    const hash = await bcrypt.hash(password, 12);

    `

    Argon2:

    `javascript

    // Memory: 64MB, Time: 3 iterations, Parallelism: 4

    const hash = await argon2.hash(password, {

    memoryCost: 65536,

    timeCost: 3,

    parallelism: 4

    });

    ``

    Password Verification Flow

  • User submits password
  • Retrieve stored hash from database
  • Hash submitted password with same algorithm
  • Compare hashes using constant-time function
  • Return success/failure
  • Additional Security Measures

  • Rate limiting: Prevent brute force attacks
  • Account lockout: After failed attempts
  • Password requirements: Minimum length, complexity
  • Breach detection: Check against known compromised passwords
  • Two-factor authentication: Additional security layer
  • Summary

    For secure password storage in 2025:

  • Use Argon2id if available (most secure)
  • Use bcrypt as a reliable fallback
  • Never use MD5, SHA-1, or plain SHA-256
  • Adjust work factors based on your hardware
  • Implement proper rate limiting and monitoring
  • Try HashSpark

    Generate SHA-1, SHA-256, SHA-384, and SHA-512 hashes instantly with our free online tool.

    Generate Hashes Now