Here's a step-by-step approach for securely storing passwords in a database, focusing on best practices, encryption, and hashing.
Best Practices for Storing Passwords
1. Use Strong Cryptographic Hashing Algorithms
-
Hashing algorithms like bcrypt, scrypt, and Argon2 are specifically designed for password storage. These algorithms are resistant to brute-force attacks because they are computationally expensive and include mechanisms to slow down hash calculations.
- bcrypt: A widely-used algorithm that automatically handles salting and is designed to be slow to thwart brute-force attacks.
- scrypt: Similar to bcrypt but also memory-intensive, which adds further resistance to attacks that use specialized hardware (e.g., GPUs, FPGAs).
- Argon2: A modern password hashing algorithm that won the Password Hashing Competition (PHC). It is considered highly secure, allowing adjustments to both time and memory complexity.
Avoid older, broken algorithms like MD5 or SHA1 for password hashing, as they are vulnerable to collision attacks.
2. Salting the Hash
3. Use Peppering (Optional)
4. Key Stretching
-
If you must use a faster algorithm (such as SHA256), implement key stretching. This involves applying the hash function multiple times to slow down the computation. The more rounds, the longer it takes for an attacker to compute possible hashes.
- bcrypt, scrypt, and Argon2 handle key stretching by default.
How to Implement Password Hashing
1. Generate a Salt:
Use a cryptographically secure random number generator to generate a unique salt for each password.
import os
salt = os.urandom(16) # 16-byte random salt
2. Hash the Password with Salt:
Use a hashing function like bcrypt to combine the password and salt.
import bcrypt
password = b"my_secure_password"
salt = bcrypt.gensalt() # Generates a new salt internally
hashed_password = bcrypt.hashpw(password, salt)
3. Store the Salt and Hashed Password:
Store the salt and the hashed password in the database. Both should be kept secure.
4. Verifying Password:
When a user attempts to log in, you retrieve the stored hash and salt, combine them with the user's input password, and compare the result with the stored hash.
input_password = b"user_input_password"
if bcrypt.checkpw(input_password, hashed_password):
print("Login successful")
else:
print("Invalid password")