TL;DR
Always use a randomly generated salt when hashing passwords with bcrypt. Computed salts (e.g., based on the username) are predictable and make your system vulnerable to attacks like rainbow table pre-computation.
Why Salts Matter
Salts are random data added to passwords before they’re hashed. Even if two users have the same password, their hashes will be different because of unique salts. This prevents attackers from using pre-computed tables (rainbow tables) to crack multiple passwords at once.
The Problem with Computed Salts
If you generate a salt based on something predictable – like the username or email address – an attacker can:
- Figure out the salt generation method.
- Pre-compute hashes for common passwords with those salts.
- Quickly crack many accounts.
Using Random Salts with bcrypt
- Generate a Unique Salt: Each password needs its own random salt. Most bcrypt libraries provide functions to do this automatically.
- Hash the Password: Combine the password and salt, then hash using bcrypt.
- Store Both Hash and Salt: You must store both the generated salt and the resulting hash in your database. The salt is needed to verify passwords later.
Example (Python)
Here’s how you might do it using the Python bcrypt library:
import bcrypt
def hash_password(password):
# Generate a salt
salt = bcrypt.gensalt()
# Hash the password with the salt
hashed = bcrypt.hashpw(password, salt)
return hashed, salt
def verify_password(password, stored_hash, stored_salt):
# Hash the provided password using the stored salt
hashed = bcrypt.hashpw(password, stored_salt)
# Compare the generated hash with the stored hash
return hashed == stored_hash
# Example Usage:
password = b'mysecretpassword'
hashed_password, salt = hash_password(password)
print("Hashed Password:", hashed_password.decode())
print("Salt:", salt.decode())
if verify_password(password, hashed_password, salt):
print("Password verified!")
else:
print("Incorrect password.")
Example (PHP)
Here’s how you might do it using the PHP bcrypt library:
Important Considerations
- Salt Length: Use a salt length recommended by your bcrypt library (typically 12-16 bytes).
- Storage Security: Protect the stored salts as carefully as you protect the hashes. If an attacker gets both, your system is compromised.
- Library Functions: Always use the built-in salt generation functions provided by your bcrypt library instead of trying to roll your own. They are designed for security and randomness.