Salt vs Pepper in Password Hashing
Learn the difference between a cryptographic salt and pepper, why both defend against rainbow tables and database breaches, and how to use them securely.
Introduction
In 2012, LinkedIn suffered a massive data breach where 117 million user passwords were stolen and eventually posted on the dark web. The passwords were encrypted using the SHA-1 algorithm, but they were stored without a salt. This critical omission meant that attackers could use precomputed lists of common passwords — known as rainbow tables — to crack millions of accounts in mere hours. Fast forward to today, and the baseline for password security has evolved. A modern authentication system must assume that its database will eventually be stolen. To protect users when that happens, cryptography relies on culinary-themed defenses: the salt and the pepper. While both are added to a password before hashing, they serve completely different purposes, are stored in completely different locations, and protect against entirely different attack vectors. Understanding how to apply salts and peppers correctly is the difference between a minor security incident and a catastrophic corporate breach.
What Is Password Hashing?
Before comparing salts and peppers, we must establish what password hashing is. When you create an account on a secure website, the database does not store your actual password. Instead, it runs your password through a cryptographic hash function.
A hash function is a mathematical algorithm that takes an input (your password) and transforms it into a fixed-length string of seemingly random characters. Crucially, hashing is a one-way street: it is mathematically impossible to reverse the hash back into the original password. When you log in, the system hashes the password you just typed and compares it to the hash stored in the database. If the hashes match, your password is correct.
However, if two users have the same password (e.g., “password123”), a basic hash function will output the exact same hash for both of them. Attackers exploit this using rainbow tables — massive databases of precomputed hashes for billions of common passwords. If an attacker steals a database of basic hashes, they simply look up the hash in their rainbow table to instantly reveal the original password.
What Is a Cryptographic Salt?
A salt is a unique, randomly generated string of characters added to a password before it is hashed. Every single user gets a completely different, random salt when they create an account.
The system concatenates the salt and the password together (e.g., salt + password), hashes the combined string, and stores both the hash and the plaintext salt in the database side-by-side.
Because every user has a unique salt, two users with the identical password “password123” will now have completely different hashes. This completely neutralizes a rainbow table attack. An attacker cannot use a precomputed table; they must compute a new table for every individual user’s unique salt, which requires an immense amount of time and computing power.
Salts do not need to be secret. Their only job is to be unique. Storing them in plaintext in the database right next to the hash is exactly how they are designed to be used.
What Is a Cryptographic Pepper?
A pepper (sometimes called a secret key) is a cryptographic string added to a password alongside the salt. However, unlike a salt, a pepper is secret and it is not stored in the database.
A pepper is typically a single, site-wide secret key applied to every password. It is stored in a highly secure location completely separate from the database — such as a Key Management Service, a hardware security module, or injected via environment variables at runtime.
The purpose of a pepper is defense-in-depth against database theft. If an attacker breaches your database and downloads all the password hashes and salts, they still cannot begin cracking the passwords via brute-force because they do not have the secret pepper. To crack the passwords, the attacker must breach both the database and the separate system where the pepper is stored.
A robust password hashing architecture: the unique salt is stored alongside the hash in the database to prevent rainbow table attacks, while the secret pepper is stored in an external KMS to prevent offline cracking if the database is stolen.
Salt vs Pepper
| Feature | Cryptographic Salt | Cryptographic Pepper |
|---|---|---|
| Purpose | Prevents rainbow table attacks; ensures unique hashes. | Prevents offline cracking if the database is stolen. |
| Uniqueness | Unique per user (dynamically generated). | Usually a single site-wide secret key. |
| Secrecy | Public (not a secret). | Highly Secret. |
| Storage Location | Stored in the database alongside the hash. | Stored separately (e.g., KMS, HSM, environment config). |
| Rotation | Never rotated (a new one is generated on password change). | Can be rotated, but requires careful key management. |
| Implementation | Built-in automatically by modern algorithms like bcrypt. | Implemented manually by the developer (usually via HMAC). |
Real-World Use Cases
Thwarting SQL Injection data dumps: The most common way databases are stolen is via SQL injection vulnerabilities. When an attacker extracts a user table, they get the hashes and the salts. If the application is using a secret pepper stored in an AWS KMS or Azure Key Vault, the database dump is effectively useless to the attacker. They cannot run offline dictionary attacks (using tools like Hashcat) because every cracking attempt requires the missing pepper.
Compliance with NIST Identity Guidelines: The US National Institute of Standards and Technology (NIST) Special Publication 800-63B sets the global standard for digital identity. It explicitly mandates that all stored passwords must be salted with at least 32 bits of random data (though 128 bits is standard) and hashed using a memory-hard function. It also strongly recommends the use of a secret key (pepper) applied as an HMAC to further secure the stored secrets.
Common Mistakes to Avoid
Using fast algorithms like SHA-256. A common mistake is using standard hashing algorithms like SHA-256 or SHA-512 for passwords. These algorithms are designed for speed — a modern GPU can calculate billions of SHA-256 hashes per second, making brute-force attacks trivial. You must use a slow, key derivation function specifically designed for passwords, such as Argon2id (the current industry standard), bcrypt, or scrypt. These algorithms have a configurable “work factor” that intentionally slows down the hashing process to thwart brute-force attempts.
Reusing salts or using predictable salts. A salt must be generated using a cryptographically secure pseudorandom number generator (CSPRNG) at the exact moment the password is created. Do not use the user’s username or email as a salt. If a user changes their email, the salt changes, invalidating the hash. Furthermore, usernames are predictable, defeating the randomness requirement of a salt.
Appending the pepper instead of using HMAC. In the past, developers would simply concatenate the pepper (e.g., hash(pepper + salt + password)). This is vulnerable to subtle cryptographic flaws. The modern, secure approach is to use a Keyed-Hash Message Authentication Code (HMAC). First, calculate an HMAC of the password using the secret pepper as the HMAC key. Then, pass the resulting HMAC output to your password hashing algorithm (like bcrypt) to handle the salting and stretching.
Getting Started
To implement secure password storage in a modern application, you do not need to invent your own cryptography. Use established, well-tested libraries.
First, select Argon2id or bcrypt as your hashing algorithm. These algorithms automatically handle generating cryptographically secure salts and storing them safely alongside the hash output. You do not need to write code to generate or manage salts yourself; the library handles it.
Second, implement a pepper using HMAC-SHA256. When a user submits a password, before passing it to your bcrypt library, calculate the HMAC of the password using your secret pepper. Store your pepper securely as an environment variable or retrieve it dynamically from a Key Management Service.
By combining a slow hashing algorithm, automatic unique salting, and a securely managed pepper, you ensure that even in a worst-case scenario where your database is compromised, your users’ passwords remain mathematically secure against cracking attempts. To understand how the system manages the secret pepper in memory, read our guide on Hardware Security Modules.
FAQ
Common questions — answered in plain English.
What is a cryptographic salt?
What is a cryptographic pepper?
Should I use both a salt and a pepper?
How long should a salt be?
Is a pepper the same as a master key?
What hashing algorithm should I use?
References
- [1]
- [2]OWASP Password Storage Cheat SheetOWASP, 2023
- [3]
- [4]How to Safely Store a PasswordCrackStation, 2020
- [5]