Salt (Cryptographic)
A random value added to a password before hashing to ensure that identical passwords produce different hash outputs. Each password should have a unique salt. Salts defeat rainbow table attacks and ensure that breaching one hashed password reveals nothing about others.
A cryptographic salt is a random value that is concatenated with a password or other input before hashing. Even if two users choose the same password, their salts will differ, resulting in completely different stored hashes. Salts eliminate the effectiveness of precomputed rainbow table attacks and make parallelized brute-force attacks significantly more expensive.
Why Salts Are Necessary
Without salts, identical passwords produce identical hashes:
hash("password123") = "482c811da5d5b4bc6d497ffa98491e38"
hash("password123") = "482c811da5d5b4bc6d497ffa98491e38"
If an attacker obtains a hash database and cracks one hash, they have cracked all users with that password. Without salts, they can also use precomputed tables (rainbow tables) to look up hashes instantly.
With salts, each hash is unique:
hash("password123" + "xJ9k2mPq") = "a1b2c3..."
hash("password123" + "nZ4r8vKs") = "d4e5f6..."
Automatic Salting in bcrypt
bcrypt handles salting automatically. The salt is generated internally and stored in the hash string:
$2b$12$LQv3c1yqBWVHxkd0LHAkCOYz6TtxMQJqhN8/LewdBPj0osBzVF84a
^^^^^^^^^^^^^^^^^^^^^
22-char salt (128 bits, Base64)
import bcrypt from "bcrypt";
// Salt is generated and embedded automatically
const hash = await bcrypt.hash("password123", 12);
// Verification extracts the salt from the stored hash
const isValid = await bcrypt.compare("password123", hash); // true
Manual Salting (for raw hash functions)
When using SHA-256 or similar for non-password use cases:
// Generate a random salt
const salt = crypto.getRandomValues(new Uint8Array(16));
const saltHex = [...salt].map(b => b.toString(16).padStart(2, "0")).join("");
// Combine salt with input
const salted = saltHex + input;
const hash = await sha256(salted);
// Store: saltHex + ":" + hash
const stored = `${saltHex}:${hash}`;
Common Mistakes
- Shared salt: using the same salt for all users defeats the purpose
- Short salt: use at least 128 bits (16 bytes) of randomness
- Predictable salt: salts must come from a CSPRNG, not
Math.random() - Secret salt ("pepper"): adding a server-side secret to the hash is a separate technique — useful but not a replacement for per-user salts
Salt Length Recommendations
OWASP recommends:
- At least 128 bits (16 bytes) of random data
- Generated with a cryptographically secure random number generator
- Unique per user and per password change
For password hashing, use bcrypt or Argon2 — they handle salting correctly by design.