Best practices when storing passwords

Best Practices for Storing Passwords

When storing user passwords, security is paramount. Poor password storage practices can lead to breaches where user data is compromised, leading to stolen accounts, identity theft, and other malicious activities. Here are the best practices for securely storing passwords:


1. Never Store Passwords in Plain Text


2. Use Strong Hashing Algorithms

Recommended Hashing Algorithms:

These algorithms are designed for password hashing because they are slow by design, making brute-force attacks much harder.

Example using bcrypt:

import bcrypt

# Hash a password
password = b"supersecretpassword"
hashed_password = bcrypt.hashpw(password, bcrypt.gensalt())

# Verify a password
bcrypt.checkpw(password, hashed_password)

3. Use a Salt for Each Password

A salt is a random string of data added to a password before hashing it. The salt ensures that even if two users have the same password, their hashes will be different. This protects against rainbow table attacks, which use precomputed hash values to crack passwords.

Example of Manual Salting with a Simple Hash:

import hashlib
import os

# Generate a random salt
salt = os.urandom(16)

# Combine password with salt and hash
password = b"supersecretpassword"
hashed_password = hashlib.pbkdf2_hmac('sha256', password, salt, 100000)

4. Use Adaptive Hashing Functions

Adaptive hashing functions like bcrypt, Argon2, and PBKDF2 allow you to adjust the hashing difficulty (through cost factors or iterations) as hardware improves. This helps maintain security in the long term, as attackers' hardware becomes more powerful.


5. Pepper Your Passwords

Example:

pepper = "randomPepperString"

# Combine password, salt, and pepper before hashing
password = "supersecretpassword"
salt = os.urandom(16)
peppered_password = password + pepper
hashed_password = hashlib.pbkdf2_hmac('sha256', peppered_password.encode(), salt, 100000)

6. Use Multi-Factor Authentication (MFA)

Even with securely stored passwords, a breach can still happen. Adding an extra layer of protection through multi-factor authentication (MFA) ensures that even if the password is compromised, attackers cannot log in without another factor (such as a code from an app or SMS).


7. Enforce Strong Password Policies


8. Rate-Limit Login Attempts

To prevent brute-force attacks, implement rate-limiting or exponential backoff on failed login attempts. This makes it harder for attackers to guess passwords by trying many combinations.


9. Implement Secure Password Reset Mechanisms


10. Regularly Update Your Hashing Algorithm

As computational power increases, weaker hashing algorithms can become vulnerable over time. It’s important to regularly review and update the hashing algorithm you're using. If transitioning from an old algorithm (e.g., MD5 or SHA-1) to a modern one (e.g., bcrypt or Argon2), you can update user passwords the next time they log in.


11. Store Password Hashes in Secure Environments


12. Avoid Reversible Encryption for Password Storage

While it might be tempting to encrypt passwords instead of hashing them (allowing for recovery), this is a bad practice. Encryption is reversible, and if the encryption key is exposed, all user passwords could be compromised. Hashing, on the other hand, is irreversible, making it more secure.


Summary of Best Practices: