Password

Best Practices for Securely Storing Hashed Passwords

By Karuvigal Engineering

In the modern cybersecurity landscape, database breaches are not a question of 'if', but 'when'. When a hacker gains unauthorized access to your user table, the only thing standing between them and your users' real-world accounts is the cryptographic strength of your password hashes. Plaintext is a relic of the past, and simple MD5 or SHA-1 hashes are now easily cracked in seconds. This technical guide explores the state-of-the-art in secure password storage, moving from basic salting to the memory-hard complexity of Argon2 and the operational defense-in-depth provided by peppering. Learn how to implement a storage architecture that remains secure even if your database is leaked to the dark web.

How It Works

  1. 1Unique Salt Generation: A cryptographically random salt (16+ bytes) is generated for *every single user* to prevent rainbow table attacks.
  2. 2Memory-Hard Hashing: The password and salt are processed through an algorithm like Argon2id, which requires significant RAM to compute, rendering GPU clusters ineffective.
  3. 3Work Factor Scaling: The algorithm is configured with 'cost factors' (iterations, memory, parallelism) that are tuned to the server's hardware capability.
  4. 4Secure Concatenation: The resulting hash, salt, and parameters are stored in the database in a standardized format (like Modular Crypt Format).
  5. 5Zero-Memory Cleanup: Sensitive plaintext password buffers are cleared from application memory as soon as the hashing process completes.

Key Features

Argon2id (Winner of the Password Hashing Competition) compliance
BCrypt and SCrypt legacy support with automatic migration paths
Per-user unique salts (CSPRNG-sourced)
Work-factor auto-scaling based on hardware evolution
Defense-in-depth via Hardware Security Modules (HSM) or Peppers

When to Use This Tool

  • B2C Web Applications: Protecting millions of consumer credentials from database dumps.
  • Enterprise IAM: Securing internal corporate identities across distributed directories.
  • Financial Platforms: Implementing high-assurance storage for banking and trading accounts.
  • SaaS Multi-tenancy: Ensuring that a breach of one tenant's logic doesn't compromise global hashes.
  • IoT Device Security: Managing local administrative credentials on edge devices.

Why Choose Karuvigal?

GPU Cracking Immunity
Rainbow Table Protection
Quantifiable Security Strength
Standardized Industry Alignment
Future-Proof Iteration Scaling

The Fall of Simple Hashing

Many legacy systems still use SHA-256 for passwords. While SHA-256 is a secure algorithm for data integrity, it is a 'fast' hash. It was designed to check large files in milliseconds. This speed is a weakness for passwords. A modern GPU rig can test billions of SHA-256 hashes per second. This means a 10-character password can be cracked in days. Secure password storage *must* be slow. Algorithms like Argon2 and BCrypt include a 'cost factor' that forces the CPU to do significant work, slowing down a cracker to just a few dozen guesses per second per card.

Salting: Personalized Protection

Without a salt, two users with the same password ('123456') would have the same hash in your database. An attacker with a 'Rainbow Table' (a precomputed list of millions of hashes) could instantly identify every user with a common password. A 'Salt' is a random string added to the password *before* hashing. Because the salt is unique to each user, the same password will result in a completely different hash. This forces the attacker to build a new, person-specific rainbow table for every single user, which is computationally impossible.

Argon2id: The Gold Standard

Argon2 was the winner of the 2015 Password Hashing Competition. It is 'memory-hard', meaning it requires a large block of RAM to calculate the hash. While GPUs have thousands of cores, they have very little memory per core. By requiring 64MB or 128MB of RAM for a single hash calculation, Argon2 kills the advantage of GPU/ASIC cracking rigs. The 'id' variant of Argon2 is the recommended standard because it provides resistance against both GPU-based cracking and side-channel timing attacks.

// Using Argon2 in Node.js
const argon2 = require('argon2');

async function hashPassword(plainText) {
  const hash = await argon2.hash(plainText, {
    type: argon2.argon2id,
    memoryCost: 2 ** 16, // 64MB
    timeCost: 3,
    parallelism: 1
  });
  return hash;
}

Developer Tip

  • Use Argon2id for all new projects. It is the objectively superior choice in 2026.
  • Always set your memory cost as high as your server can handle while maintaining a <500ms login time.

The Secret Spice: Peppering

While salts are stored in the database next to the hash, a 'Pepper' is a secret key stored *outside* the database (e.g., in an environment variable or a Key Vault). When you hash a password, you include the pepper. If an attacker steals your database but fails to compromise your application server, they cannot even *attempt* to crack the hashes because they are missing the pepper. This 'defense-in-depth' strategy provides a final, critical layer of safety for high-value targets.

Frequently Asked Questions

Ready to Try It?

Start using our free Password tool now

Open Password Tool