Introduction
Passwords are a primary target for attackers. If a password database is compromised, poorly stored passwords can be exposed immediately. The safest approach is never to store plaintext passwords, and instead store encrypted hashes with a unique salt for each user.
Why Password Storage Matters
Passwords are a primary target for attackers. If a password database is compromised, poorly stored passwords can be exposed immediately. The safest approach is never to store plaintext passwords, and instead store encrypted hashes with a unique salt for each user.
Hashing vs Encryption
Hashing is a one-way function: you can transform a password into a fixed-size digest, but you cannot reverse it back to the original password. Encryption is reversible if you have the key, so it is not suited for password storage.
const hashedPassword = await bcrypt.hash(password, 12)
Use a proven algorithm like bcrypt, Argon2, or scrypt. These algorithms are intentionally slow and resistant to brute force attacks.
Why Salting Is Essential
A salt is a random string added to the password before hashing. It ensures that identical passwords produce different hashes, preventing attackers from using precomputed tables or identifying users with the same password.
Secure Login Flow
- User submits password.
- Server fetches the stored salt and hashed password.
- Server hashes the provided password with the same salt.
- Server compares the new hash to the stored hash.
Practical Tips
- Use HTTPS for all authentication traffic.
- Implement rate limiting and account lockouts.
- Rotate keys and salts carefully.
- Use a separate, secure secrets management system for keys.
Frequently Asked Questions
Why should I never store plaintext passwords?
If your database is compromised, plaintext passwords are immediately exposed to attackers. Storing plaintext passwords also means anyone with database access—including developers and administrators—can read user passwords. Hashing ensures that even if the database leaks, the actual passwords remain protected.
What is the difference between hashing and encryption?
Hashing is a one-way function that produces a fixed-size digest from input data and cannot be reversed. Encryption is a two-way process that requires a key to decrypt. For password storage, you want hashing because you never need to retrieve the original password—you only need to verify it.
What is bcrypt and why is it recommended?
Bcrypt is a password hashing algorithm designed to be intentionally slow and computationally expensive. It includes built-in salt generation and a configurable work factor. The slowness is a feature—it makes brute-force attacks impractical by requiring significant time and resources for each password guess.
What is a salt in password hashing?
A salt is a random string added to each password before hashing. It ensures that two users with the same password get different hashes, preventing attackers from using precomputed rainbow tables. Each user should have a unique, randomly generated salt stored alongside their hash.
Which is better: bcrypt, scrypt, or Argon2?
All three are recommended over plain hash functions. Argon2 is the newest and won the Password Hashing Competition, offering the best resistance to GPU-based attacks. Scrypt is designed to be memory-hard. Bcrypt is the most widely supported and battle-tested. For most applications, bcrypt with a sufficient work factor is excellent.
How many rounds should I use for bcrypt?
The bcrypt work factor (cost factor) determines how many rounds of hashing are performed. A factor of 12 is a good starting point, taking roughly 250ms per hash on modern hardware. Increase the factor over time as hardware gets faster—the goal is to keep hash computation around 200-500ms.
Should I implement password hashing myself?
No. Never implement cryptographic algorithms yourself. Use well-tested libraries like bcrypt, argon2, or scrypt packages for your programming language. These libraries handle salt generation, key stretching, and constant-time comparison correctly, avoiding subtle vulnerabilities that manual implementations often have.
What is account lockout and why do I need it?
Account lockout temporarily disables an account after a certain number of failed login attempts. It prevents brute-force attacks by limiting how many passwords an attacker can try. Combine it with rate limiting on the login endpoint and consider using CAPTCHAs after several failed attempts.
How does HTTPS protect password storage?
HTTPS encrypts the communication between the client and server, preventing attackers from intercepting passwords in transit. Without HTTPS, an attacker on the same network can capture plaintext passwords before they reach your server, regardless of how securely you store them in your database.
What is a password hashing work factor?
The work factor is a parameter that controls how computationally expensive the hashing process is. Higher work factors make hashing slower, which is intentional—it makes brute-force attacks exponentially more expensive. As hardware improves, you should increase the work factor to maintain the same level of protection.
Can I upgrade password hashing algorithms for existing users?
Yes. When a user next logs in successfully, re-hash their password with the new algorithm and update the stored hash. This is called hash migration or hash upgrading. You can run the old algorithm first to verify, then hash with the new algorithm. This approach avoids forcing a password reset for all users.
Conclusion
Storing passwords securely is one of the most important tasks for any web application. Hash every password, use a unique salt, choose a strong algorithm, and never store plaintext passwords. These steps protect your users and reduce the risk of a full account compromise.
Frequently asked questions
Why should I never store plaintext passwords?
If your database is compromised, plaintext passwords are immediately exposed to attackers. Storing plaintext passwords also means anyone with database access—including developers and administrators—can read user passwords. Hashing ensures that even if the database leaks, the actual passwords remain protected.
What is the difference between hashing and encryption?
Hashing is a one-way function that produces a fixed-size digest from input data and cannot be reversed. Encryption is a two-way process that requires a key to decrypt. For password storage, you want hashing because you never need to retrieve the original password—you only need to verify it.
What is bcrypt and why is it recommended?
Bcrypt is a password hashing algorithm designed to be intentionally slow and computationally expensive. It includes built-in salt generation and a configurable work factor. The slowness is a feature—it makes brute-force attacks impractical by requiring significant time and resources for each password guess.
What is a salt in password hashing?
A salt is a random string added to each password before hashing. It ensures that two users with the same password get different hashes, preventing attackers from using precomputed rainbow tables. Each user should have a unique, randomly generated salt stored alongside their hash.
Which is better: bcrypt, scrypt, or Argon2?
All three are recommended over plain hash functions. Argon2 is the newest and won the Password Hashing Competition, offering the best resistance to GPU-based attacks. Scrypt is designed to be memory-hard. Bcrypt is the most widely supported and battle-tested. For most applications, bcrypt with a sufficient work factor is excellent.
How many rounds should I use for bcrypt?
The bcrypt work factor (cost factor) determines how many rounds of hashing are performed. A factor of 12 is a good starting point, taking roughly 250ms per hash on modern hardware. Increase the factor over time as hardware gets faster—the goal is to keep hash computation around 200-500ms.
Should I implement password hashing myself?
No. Never implement cryptographic algorithms yourself. Use well-tested libraries like bcrypt, argon2, or scrypt packages for your programming language. These libraries handle salt generation, key stretching, and constant-time comparison correctly, avoiding subtle vulnerabilities that manual implementations often have.
What is account lockout and why do I need it?
Account lockout temporarily disables an account after a certain number of failed login attempts. It prevents brute-force attacks by limiting how many passwords an attacker can try. Combine it with rate limiting on the login endpoint and consider using CAPTCHAs after several failed attempts.
How does HTTPS protect password storage?
HTTPS encrypts the communication between the client and server, preventing attackers from intercepting passwords in transit. Without HTTPS, an attacker on the same network can capture plaintext passwords before they reach your server, regardless of how securely you store them in your database.
What is a password hashing work factor?
The work factor is a parameter that controls how computationally expensive the hashing process is. Higher work factors make hashing slower, which is intentional—it makes brute-force attacks exponentially more expensive. As hardware improves, you should increase the work factor to maintain the same level of protection.
Can I upgrade password hashing algorithms for existing users?
Yes. When a user next logs in successfully, re-hash their password with the new algorithm and update the stored hash. This is called hash migration or hash upgrading. You can run the old algorithm first to verify, then hash with the new algorithm. This approach avoids forcing a password reset for all users.