TL;DR
Storing usernames (emails) and passwords together in a single hashed field is insecure. This guide explains how to separate them, hash each individually with strong algorithms, and store the hashes securely for better cyber security.
Solution Guide: Separating & Hashing User Credentials
- Understand the Risk
- Combining usernames and passwords before hashing creates a ‘rainbow table’ vulnerability. If one user has a weak password, attackers can potentially compromise other accounts using similar patterns.
- It makes salt application more difficult and less effective.
- Database Schema Change
- Replace the existing single ‘credentials’ field with two fields:
username: VARCHAR(255), UNIQUE index recommended.password_hash: VARCHAR(255) or larger, depending on your hashing algorithm (see step 3).
- Choose a Strong Hashing Algorithm
- Recommended options:
- bcrypt: A well-established algorithm with automatic salting.
- Argon2: Considered the most secure option, but may require more computational resources.
- scrypt: Another strong option, offering good security and performance.
- Hashing Passwords on Registration
- Verifying Passwords on Login
- Salting (if not using bcrypt/Argon2)
- Generate a random salt for each user. Store the salt alongside the hash (e.g., in another database column).
- Concatenate the salt with the password before hashing:
hash(salt + password) - Security Considerations
- Key Stretching: Algorithms like bcrypt and Argon2 perform key stretching, making brute-force attacks more difficult.
- Regular Updates: Keep your hashing libraries up to date to benefit from the latest security improvements.
- Rate Limiting: Implement rate limiting on login attempts to prevent brute-force attacks.
- Two-Factor Authentication (2FA): Consider adding 2FA for an extra layer of cyber security.
Modify your database to store usernames (emails) and password hashes in separate columns.
Use modern, robust password hashing algorithms. Avoid older algorithms like MD5 and SHA1.
When a new user registers, hash their password before storing it in the database.
# Example using Python and bcrypt
import bcrypt
def hash_password(password):
salt = bcrypt.gensalt()
hashed_password = bcrypt.hashpw(password.encode('utf-8'), salt)
return hashed_password.decode('utf-8')
# Example usage:
new_user_password = "MySecurePassword123"
hashed_password = hash_password(new_user_password)
print(hashed_password) # Store this in the password_hash column
When a user logs in, retrieve their stored password_hash and compare it to the hash of the entered password.
# Example using Python and bcrypt
import bcrypt
def verify_password(entered_password, stored_hash):
return bcrypt.checkpw(entered_password.encode('utf-8'), stored_hash.encode('utf-8'))
# Example usage:
stored_hash = "$2b$12$EXAMPLEHASHEDPASSWORD"
user_entered_password = "MySecurePassword123"
is_valid = verify_password(user_entered_password, stored_hash)
print(is_valid) # True if the password matches
If your chosen algorithm doesn’t handle salting automatically, you must add a unique salt to each password before hashing.

