To safeguard passwords against brute-force and dictionary attacks, it's essential to employ both salting and hashing techniques. Salting adds unique data to each password before hashing, ensuring that even identical passwords result in distinct hashes. Hashing then transforms the salted password into a fixed-size string, which is computationally infeasible to reverse.
1. Optimal Hashing Algorithms for Password Storage
Selecting the right hashing algorithm is crucial for security. The following algorithms are widely recognized for their effectiveness in password hashing:
-
Argon2: Winner of the Password Hashing Competition in 2015, Argon2 is designed to be memory-intensive, making it resistant to GPU-based attacks. It offers configurable parameters for memory usage, execution time, and parallelism, allowing fine-tuning based on security requirements.
-
bcrypt: Based on the Blowfish cipher, bcrypt incorporates a work factor (cost) that determines the hashing complexity, making it adaptable to increasing computational power. It's widely supported and has been a reliable choice for many years.
-
scrypt: Designed to be both memory and CPU-intensive, scrypt is effective against hardware attacks. It's particularly useful when resistance to large-scale custom hardware attacks is a priority.
-
PBKDF2: Part of RSA Laboratories' Public-Key Cryptography Standards, PBKDF2 applies a pseudorandom function (such as HMAC) to the password along with a salt and repeats the process multiple times to produce a derived key. While it's widely adopted and configurable, it's less resistant to GPU attacks compared to the other algorithms mentioned.
2. Proper Generation and Storage of Salts
Salts are random values added to passwords before hashing to ensure that identical passwords produce unique hashes. To implement salting securely:
-
Generation: Use a cryptographically secure random number generator to create a unique salt for each password. The salt should be sufficiently long; a length of at least 16 bytes (128 bits) is recommended.
-
Storage: Store the salt alongside the hashed password in your database. Since the salt is not a secret, its exposure doesn't compromise security. However, it must be unique for each password to prevent attackers from using precomputed hashes (rainbow tables).
3. Password Stretching Techniques
Password stretching involves applying a hashing algorithm multiple times to increase the computational effort required to verify each password. This technique slows down attackers attempting to crack passwords using brute-force methods. Algorithms like Argon2, bcrypt, scrypt, and PBKDF2 inherently support this by allowing configuration of parameters such as iteration count or cost factors. Adjusting these parameters increases the time and resources needed to compute the hash, thereby enhancing security.
4. Implementing Secure Password Hashing
Below are examples of implementing secure password hashing in Python and PHP:
Python Example Using bcrypt:
import bcrypt
# Password to be hashed
password = b"secure_password"
# Generate a salt
salt = bcrypt.gensalt()
# Hash the password with the generated salt
hashed_password = bcrypt.hashpw(password, salt)
# To verify the password
if bcrypt.checkpw(password, hashed_password):
print("Password is correct")
else:
print("Password is incorrect")
In this example, bcrypt.gensalt() generates a salt, and bcrypt.hashpw() hashes the password with the salt. The checkpw() function verifies if the provided password matches the hashed password.
PHP Example Using password_hash:
<?php
// Password to be hashed
$password = 'secure_password';
// Hash the password using the default algorithm (bcrypt) with a cost of 10
$hashed_password = password_hash($password, PASSWORD_DEFAULT, ['cost' => 10]);
// To verify the password
if (password_verify($password, $hashed_password)) {
echo 'Password is correct';
} else {
echo 'Password is incorrect';
}
?>
Here, password_hash() creates a hashed password using bcrypt by default, and password_verify() checks if the given password matches the hashed password.
By integrating these practices—selecting a robust hashing algorithm, properly generating and storing salts, and implementing password stretching—you can significantly enhance the security of your password storage system.