What exactly is a salt?
A salt is a random string of bytes generated by the computer.
Example:
Password:
MyPassword@123
Salt:
X7Ak29Pq8LmN2RsT
The hashing algorithm works with:
MyPassword@123 + X7Ak29Pq8LmN2RsT
instead of just:
MyPassword@123
The name comes from cooking.
Imagine two people make the same soup.
Without salt:
Soup A ---> Same taste
Soup B ---> Same taste
Add different spices (or "salt"):
Soup A + Salt A → Different taste
Soup B + Salt B → Different taste
Similarly:
Password + Random Salt
produces a unique hash, even if the password itself is the same.
Suppose three users choose the same password:
Password = admin123
Using SHA256 without salt:
SHA256(admin123)
↓
8c6976e5b541...
Database:
| User | Password | Hash |
|---|---|---|
| Alice | admin123 | 8c6976... |
| Bob | admin123 | 8c6976... |
| Charlie | admin123 | 8c6976... |
An attacker immediately sees that all three users share the same password.
Alice:
Password:
admin123
Salt:
abc123xyz
Hash becomes:
bcrypt(admin123 + abc123xyz)
↓
$2b$12$...
Bob:
Password:
admin123
Salt:
kL98MnPQ
Hash becomes:
bcrypt(admin123 + kL98MnPQ)
↓
$2b$12$...
Charlie's salt:
7HjkL20P
Hash becomes:
$2b$12$...
Now the database looks like:
| User | Password | Salt | Hash |
|---|---|---|---|
| Alice | admin123 | abc123xyz | Hash A |
| Bob | admin123 | kL98MnPQ | Hash B |
| Charlie | admin123 | 7HjkL20P | Hash C |
Even though all three passwords are identical:
Hash A ≠ Hash B ≠ Hash C
Many beginners think:
"If the salt is stored in the database, can't hackers use it?"
Yes, the salt is stored with the hash, and that's perfectly fine.
A bcrypt hash looks like:
$2b$12$Gb8vMQUm8fIhgmfEjMkhZu7h3...
This string contains:
$2b$
│
├── Algorithm
12
│
├── Cost
Gb8vMQUm8fIhgmfEjMkhZu
│
├── Salt
Remaining characters
│
└── Password Hash
The salt is not secret. Its purpose is uniqueness, not secrecy.
The security comes from:
The password being unknown.
The hashing algorithm being one-way.
The computational cost of bcrypt.
Even if an attacker knows the salt, they still have to guess the password and run bcrypt for every guess.
Suppose the stored bcrypt hash is:
$2b$12$Gb8vMQUm8fIhgmfEjMkhZu7h3...
During login:
User enters:
MyPassword@123
bcrypt:
Extracts the salt from the stored hash.
Hashes the entered password using that same salt and cost.
Compares the newly computed hash with the stored hash.
If they match:
Login Successful
Otherwise:
Invalid Password
You never have to manually manage the salt when using bcrypt; it is embedded in the stored hash.
Example:
import bcrypt
salt = bcrypt.gensalt()
print(salt)
Output:
b'$2b$12$Gb8vMQUm8fIhgmfEjMkhZu'
Now hash the password:
password = b"MyPassword@123"
hashed = bcrypt.hashpw(password, salt)
print(hashed)
Output:
b'$2b$12$Gb8vMQUm8fIhgmfEjMkhZu7h3fRrQv...'
Notice that the hash begins with the same prefix as the salt because the salt is embedded into the final bcrypt hash.
Imagine every house has the same lock model.
Without salt:
Every lock uses the same key shape.
A thief who makes one master key can open every matching lock.
With salt:
Every lock has a unique internal modification.
Even if two locks look identical, each needs a different key.
The password is like the key, and the salt is the unique modification that makes each lock distinct.
Salt is a random value, not a secret password.
It is different for every user and every password hash.
It prevents identical passwords from producing identical hashes.
It protects against precomputed attacks such as rainbow tables.
With bcrypt, the salt is automatically generated, stored inside the hash, and reused during verification, so you rarely need to handle it yourself.