What is a cryptographic salt and why is it crucial?
A salt is a random string combined with a password before hashing. Without salt, two users with same password would have identical hashes, enabling rainbow table attacks where attackers precompute hashes of millions of common passwords.
With salt, even if two users use 'password123', their hashes are completely different because each has unique salt: hash(password123 + user1_salt) ≠ hash(password123 + user2_salt). This makes precomputing hash tables infeasible.
Salt does NOT need to be secret—it's stored in plain text alongside hash in your database. Its function isn't hiding, but guaranteeing uniqueness. Typical salt is 16-32 bytes (128-256 bits) generated from cryptographically secure source like crypto.randomBytes() in Node or secrets.token_bytes() in Python.
Correct salt + hash implementation
Never implement your own hashing system. Use battle-tested libraries: bcrypt (recommended for passwords), Argon2 (PHC 2015 competition winner), or scrypt. These libraries automatically generate salt and include it in output.
Example with bcrypt in Node: bcrypt.hash(password, 12) generates string like '$2b$12$[salt][hash]'. The '12' is cost factor (2^12 rounds). Higher number = more secure but slower. 12-14 is reasonable in 2024. Don't use SHA-256 directly for passwords—it's too fast and allows massive brute force.
When verifying: bcrypt.compare(enteredPassword, storedHash) automatically extracts salt from stored hash and recomputes. If it matches, password is correct. Unique salt per user makes each verification independent—compromising one hash doesn't compromise others.
Salts in other security contexts
Salts are also used in key derivation (KDF), session tokens, and preventing timing attacks. In JWT, for example, random salt in payload makes tokens with same data generate different signatures, complicating pattern analysis.
For password recovery tokens, generate cryptographically strong salt (32+ bytes), hash it, save hash in DB, and send original salt by email. When user returns with token, you rehash and compare with stored. Never save token in plain text in database.
In symmetric encryption (AES), 'initialization vectors' (IV) serve similar function to salt: ensure same message encrypted with same key produces different ciphertexts. IV must be random per message and transmitted in clear alongside ciphertext.
Common mistakes with salts and how to avoid them
Mistake 1: Using same salt for all users. This negates benefit—attacker can precompute hashes for that specific salt. Solution: unique salt per user, generated at registration.
Mistake 2: Short or predictable salts. Using timestamp or user_id as salt is insecure. Solution: minimum 128 bits (16 bytes) of cryptographic randomness from sources like /dev/urandom or Web Crypto API.
Mistake 3: Hashing password then adding salt. Order is password + salt → hash, not hash(password) + salt. Concatenation must occur before hashing. Bcrypt and Argon2 handle this correctly for you.
Mistake 4: Reusing salts in password rotation. When user changes password, generate new salt. Don't reuse previous—you want each hash independent of its history.