TL;DR
Hashing a hash of your password doesn’t make it more secure – in fact, it makes it less secure. It provides no real benefit and introduces potential vulnerabilities. Use a strong, modern key derivation function (KDF) like Argon2id or bcrypt instead.
Why Double Hashing is Bad
The idea behind hashing a hash of a password seems logical at first: add another layer of protection. However, it’s fundamentally flawed and doesn’t achieve the intended security goals. Here’s why:
- No Increased Work Factor: A hash function is designed to be fast. Hashing twice (or more) doesn’t significantly increase the computational effort required for an attacker to crack it.
- Vulnerability to Length Extension Attacks: Some hash functions are susceptible to length extension attacks, which become easier with multiple hashes.
- False Sense of Security: It gives a misleading impression that the system is more secure than it actually is.
Step-by-Step Solution: Replace Double Hashing
- Understand Key Derivation Functions (KDFs): KDFs are specifically designed for password hashing. They take a password and salt as input and produce a strong, fixed-size hash that is computationally expensive to compute.
- Choose a Strong KDF:
- Argon2id: Generally considered the most secure option. It’s resistant to GPU cracking and side-channel attacks.
- bcrypt: A well-established and widely used KDF.
- scrypt: Another good option, but Argon2id is preferred.
- Implement the Chosen KDF: Use a library in your programming language to implement the KDF correctly. Do not attempt to write your own hashing algorithm!
Example using Python and Argon2id
This example uses the argon2-cffi library. You’ll need to install it first: pip install argon2-cffi.
import argon2
pw = "mysecretpassword"
salt = argon2.generate_salt()
hash = argon2.hash(pw, salt=salt)
print("Hash:", hash)
# Verify the password
try:
argon2.verify(hash, pw)
print("Password verified!")
except argon2.exceptions.VerifyError:
print("Incorrect password.")
Example using PHP and bcrypt
PHP’s password_hash() and password_verify() functions provide a simple way to use bcrypt.
<?php
$password = "mysecretpassword";
$hash = password_hash($password, PASSWORD_BCRYPT);
if (password_verify("mysecretpassword", $hash)) {
echo "Password verified!";
} else {
echo "Incorrect password.";
}
?>
Step 3: Store the Salt with the Hash
The salt is crucial for security. Always store it alongside the hash in your database. The Argon2id example above demonstrates this.
Step 4: Update Existing Passwords (Important!)
- Iterate through all user accounts.
- Retrieve each password and its current salt (if any).
- Re-hash the password using the chosen KDF with a new, randomly generated salt.
- Update the database with the new hash and salt.
This is a critical step to ensure all passwords are protected by the stronger hashing algorithm.
Step 5: Configuration
Configure your KDF appropriately. Argon2id has parameters for memory cost, time cost and parallelism. Increase these values (within reasonable limits) to increase the computational effort required for cracking. bcrypt also has a cost parameter; higher costs are more secure but slower.
cyber security Best Practices
- Use strong salts: Salts should be unique, randomly generated, and sufficiently long (at least 16 bytes).
- Regularly review your cyber security practices: Stay up-to-date with the latest vulnerabilities and best practices.
- Consider multi-factor authentication (MFA): Adds an extra layer of security beyond just a password.