Salt in Password Hashing
What is a salt in password hashing, how it prevents rainbow table and dictionary attacks, proper salt generation, and how modern algorithms like bcrypt handle salts automatically.
Detailed Explanation
A salt is a random value that is combined with a password before hashing, ensuring that identical passwords produce different hash outputs. Salting is one of the most important defenses in password security, preventing precomputation attacks and making each password hash unique.
The problem salts solve:
Without salts, the same password always produces the same hash. If 1,000 users all choose "password123", all 1,000 rows in the database contain the same hash value. An attacker who cracks one has cracked all of them. Worse, the attacker can precompute a dictionary of common password hashes (a rainbow table) and look up hashes instantly. Salts eliminate both problems: each user's hash is unique because each user has a unique salt.
How salts are used:
The salt is generated using a cryptographically secure random number generator (e.g., /dev/urandom, crypto.randomBytes(), SecureRandom). It is combined with the password and fed into the hash function: hash(salt || password) or hash(password || salt). The salt is stored alongside the hash in the database, typically in the same field. The salt does not need to be secret; its purpose is to ensure uniqueness, not to add entropy to the password itself.
Salt requirements:
A good salt should be at least 128 bits (16 bytes) of cryptographically random data. Each password must have its own unique salt; never reuse salts across users. Never use predictable values as salts (username, user ID, timestamps). The salt must be stored and retrievable for verification. Using a global "pepper" (a secret value shared across all passwords) adds defense-in-depth but does not replace per-user salts.
Modern implementations:
bcrypt stores the salt as part of its output string format: $2b$12$[22-char salt][31-char hash]. Argon2 similarly encodes parameters and salt in its output. When using these algorithms, salt generation and storage are handled automatically. If using PBKDF2 or raw hash functions (which you should avoid for passwords), you must manage salts manually. In that case, generate the salt with a CSPRNG, concatenate it with the password, hash with the appropriate iteration count, and store both the salt and hash together.
Common mistakes to avoid:
Using short salts (under 16 bytes), reusing the same salt for all users, using predictable salts (sequential integers, timestamps), using MD5 or SHA-256 without a proper password hashing algorithm, and forgetting to store the salt.
Use Case
Every password storage system must use unique per-user salts to prevent rainbow table attacks and ensure identical passwords produce different hash values in the database.