TL;DR
Don’t store passwords directly on your server, even encrypted! Use a strong password hashing function (like bcrypt or Argon2) with salts. Store the hashes and salts securely. Consider using a dedicated secrets management system for extra protection.
Why You Shouldn’t Store Passwords Directly
Even if you encrypt passwords, it’s risky. Encryption can be broken, keys can be stolen, or vulnerabilities discovered. Hashing is designed to be one-way – you can’t get the original password back from the hash.
Step-by-Step Guide
- Choose a Strong Password Hashing Function:
- bcrypt: A widely used and well-tested algorithm. It automatically handles salting.
- Argon2: More modern and resistant to certain attacks, but can be more complex to implement.
- Avoid older algorithms like MD5 or SHA1: These are easily cracked.
- Generate Salts:
- Hash the Passwords:
- Store the Hashes and Salts:
- Store both the hash and the salt in your database. Don’t store them together as a single string; keep them separate for better security.
- Protect your database! Use strong access controls, encryption at rest (if possible), and regular backups.
- Password Verification:
- Retrieve the salt for that user from the database.
- Hash the entered password using the retrieved salt.
- Compare the resulting hash with the stored hash. If they match, the password is correct.
- Secrets Management Systems (Recommended):
- Consider using a dedicated secrets management system like HashiCorp Vault, AWS Secrets Manager, or Azure Key Vault. These systems provide extra layers of security for sensitive data like database credentials and API keys. They handle encryption, access control, and auditing automatically.
- Regularly Review and Update:
- Keep your hashing libraries up to date to benefit from the latest security patches.
- Monitor for suspicious activity in your database.
A salt is a random string added to each password before hashing. This prevents attackers from using pre-computed tables of common passwords (rainbow tables). Each user should have a unique salt.
# Example Python with bcrypt
salt = os.urandom(16)
pwd_hash = bcrypt.hashpw(password.encode('utf-8'), salt)
Use your chosen hashing function to create a hash of each password, combined with its unique salt.
# Example PHP with Argon2
$hash = password_hash($password, PASSWORD_ARGON2ID);
When a user logs in:
# Example Python with bcrypt
hashed_password = bcrypt.hashpw(entered_password.encode('utf-8'), retrieved_salt)
if hashed_password == stored_hash:
# Password matches!
Important Considerations
- Password Complexity: Enforce strong password policies (minimum length, mixed case, numbers, symbols).
- Rate Limiting: Prevent brute-force attacks by limiting the number of login attempts.
- Two-Factor Authentication (2FA): Add an extra layer of security with 2FA.

