Why Hashing Alone Isn't Enough
A site should never store your actual password. Instead it stores a hash of it — a one-way fingerprint that cannot be reversed back into the password. At login, the site hashes what you typed and compares it to the stored hash. If they match, you are in, and the real password was never kept anywhere.
The problem is that a plain hash is deterministic: the same input always produces the exact same output. That single property opens two serious holes. First, two users with the same password — and "123456" is depressingly popular — end up with identical stored hashes, so an attacker who steals the database can instantly see which accounts share a password and crack them together. Second, and worse, attackers maintain enormous precomputed lookup tables called rainbow tables that map millions of common passwords to their hashes in advance. Against an unsalted database, cracking is reduced to a fast lookup — no real computation required.
The Salt: A Pinch of Randomness Per Password
A salt is a random value generated uniquely for each password and combined with it before hashing:
stored_hash = hash( salt + password )
The salt is then stored right alongside the hash, in plain text. Because every password gets its own random salt, the two holes close at once:
- Two users with the password "sunshine" now have different salts, so their stored hashes are completely different. An attacker can no longer tell that they share a password, and cracking one tells them nothing about the other.
- Rainbow tables become useless. A precomputed table would have to be rebuilt for every possible salt — an impossible amount of storage — so the attacker is forced back to attacking each password individually, from scratch.
That second point is the heart of it. Salting does not make any single password harder to guess; it makes precomputation impossible, so the attacker loses the massive shortcut that rainbow tables provided and must spend real effort on each account separately.
Why a Salt Doesn't Need to Be Secret
A common confusion is the assumption that the salt must be hidden. It does not — and it is stored in the clear precisely because its protection does not depend on secrecy. Even handed the salt, the attacker gains nothing they could exploit: they still cannot reverse the hash, and they still cannot reuse a precomputed table, because that table would have had to be built for this exact salt in advance, which is the very thing salting prevents. The salt's job is to make every hash unique and to force per-password work, both of which it accomplishes in full view. Secrecy was never the mechanism.
Salt vs Pepper
There is a related idea that is secret, and the two are easy to mix up:
| Salt | Pepper | |
|---|---|---|
| Unique per password? | Yes | No — one value for all |
| Stored where? | Alongside the hash, in plain text | Separately, kept secret (e.g. app config) |
| Defeats rainbow tables? | Yes | Not its purpose |
| Helps if only the DB is stolen? | Limits damage | Yes — attacker lacks the pepper |
A pepper is a single secret value applied to every password and stored outside the database, often in application configuration or a separate vault. The thinking is that many breaches expose only the database; if the pepper lives elsewhere, the attacker has the salted hashes but not the pepper, leaving a layer they cannot see. A salt and a pepper solve different problems and are often used together — the salt for uniqueness and anti-precomputation, the pepper for a secret the database dump does not reveal.
Salting Is Necessary, but Not the Whole Story
Salting fixes precomputation and reuse, but it does not make a weak password strong. Against a fast hash, an attacker who has the salt can still try billions of guesses per second for each account, and short or common passwords fall quickly. The missing ingredient is slowness. Modern password storage deliberately uses hashing functions that are intentionally slow and resource-hungry — bcrypt, scrypt, and Argon2 — so that each guess costs meaningful time and memory. A delay imperceptible to a legitimate user logging in once becomes ruinous to an attacker who must make billions of attempts.
The modern recipe, then, is the combination: a unique random salt on every password plus a slow, purpose-built password hash. The salt strips away the attacker's shortcuts; the slow hash makes the remaining brute-force work prohibitively expensive. Either alone is inadequate; together they are why a well-built system can survive a database breach without its users' passwords being trivially recovered. For the underlying distinction between a one-way hash and reversible encryption, see hashing vs encryption.
Frequently Asked Questions
What is a salt in hashing?
A random value added to a password before hashing, different for every password. It makes each stored hash unique even when two users pick the same password and stops attackers using precomputed hash tables. The salt is not secret and is stored beside the hash; its job is to make precomputation useless.
Why are passwords salted?
Without a salt, identical passwords produce identical hashes, so a stolen database reveals reused passwords and lets attackers crack many at once with rainbow tables. Salting makes each hash unique, so rainbow tables fail and every password must be attacked individually.
Does a salt need to be secret?
No. A salt is stored in plain text next to the hash and protects even when the attacker sees it. Its purpose is uniqueness and defeating precomputed tables, not secrecy. A secret value kept out of the database is called a pepper, which serves a different role.
What is the difference between a salt and a pepper?
A salt is unique per password and stored with the hash, defeating rainbow tables. A pepper is a single secret value applied to all passwords and kept separately from the database. If only the database is stolen, the pepper stays unknown, adding a layer the attacker cannot see.
Is salting enough to protect passwords?
Necessary but not sufficient. A fast hash, even salted, can be brute-forced quickly against weak passwords. Modern storage combines a unique salt with a deliberately slow function like bcrypt, scrypt, or Argon2, so each guess is expensive and large-scale cracking becomes impractical.