← Concepts

阅读中文版本

Password Hashing

Password hashing converts passwords into slow, salted verifiers with Argon2id, bcrypt, or scrypt. Fast hashes and reversible encryption are unsafe for password storage.

security

Definition

Password hashing applies a one-way, deliberately expensive key derivation function to a password with a unique salt, producing a verifier that cannot be feasibly reversed. The algorithm and cost parameters are chosen so that offline guessing is expensive while legitimate logins remain acceptable.

Context and scope

Password hashing is required for any credential store, including web applications, internal tools, and password-derived encryption keys. It is distinct from encryption and from fast message digests such as SHA-256.

Common misconceptions

  • A salted SHA-256 digest is adequate because the salt prevents rainbow tables
  • Encrypting passwords is safe when the encryption key is stored securely

Anti-patterns

  • Using a single global salt shared by every account
  • Lowering the cost factor so much that offline cracking becomes cheap

Related concepts

Related examples

Authoritative source

https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html

How password hashing works

A password hash is a one-way, deliberately slow function. The server generates a random per-user salt, combines it with the password, and runs a memory-hard algorithm such as Argon2id, bcrypt, or scrypt. It stores the algorithm, parameters, salt, and digest. Verification recomputes the hash and compares it in constant time. Salts defeat precomputed rainbow tables, while cost parameters make offline guessing expensive.

When to use it

Use password hashing whenever you store a password or derive a key from one. Never encrypt passwords, because encryption is reversible and the key becomes a single point of failure. Use Argon2id where available; bcrypt remains acceptable with a cost of at least 12 and inputs under 72 bytes. Rehash on successful login when parameters change.

Trade-offs

Higher cost slows attackers but also consumes server CPU and memory, creating a denial-of-service lever. Argon2id needs memory tuning per instance, while bcrypt has a 72-byte input limit and no memory hardness. Peppering with a KMS-held secret adds defense in depth but complicates rotation. Hashing does not protect weak passwords from credential stuffing, so add rate limiting and breached-password checks.

Example

import argon2 from 'argon2';

const hash = await argon2.hash(password, {
  type: argon2.argon2id,
  memoryCost: 19456,
  timeCost: 2,
});
const ok = await argon2.verify(hash, candidate);

A salted SHA-256 digest is still far too fast. Encryption is not hashing. A pepper is not a substitute for per-user salts. Truncating passwords silently at 72 bytes weakens bcrypt users with long passphrases. Related concepts include secret management, encryption at rest, and least privilege.