Password Hashing: Never Store Plain Text

Storing passwords as plain text puts every user at risk. Learn password hashing with bcrypt, salting, and a checklist to secure your login system.

If your database stores passwords as readable text, one breach exposes every account, and users reuse passwords everywhere. This article explains why plain text is dangerous, how password hashing solves it, and how to implement it correctly. You will leave knowing exactly what to store and what to avoid.

Why Plain Text Is Dangerous

When passwords are stored as-is, anyone who reads the database sees them: an attacker after a breach, a curious employee, or a leaked backup. Because many people reuse passwords, a single leak can compromise their email, banking, and work accounts. Storing plain text turns your app into a liability for the whole internet, not just your own service.

Encryption is not the answer either. Encryption is reversible: if you can decrypt to check a login, so can an attacker who steals the key. What you want is a one-way transformation.

What Password Hashing Does

A hash function converts a password into a fixed-length string that cannot be reversed. You never store the password. You store the hash. When a user logs in, you hash the input and compare it to the stored hash. If they match, the password was correct, and you never had to keep the original.

Why Fast Hashes Are the Wrong Tool

General-purpose hashes like MD5 or SHA-256 are built for speed. That is exactly what you do not want for passwords. An attacker with a stolen database can try billions of guesses per second against a fast hash. Password hashing needs to be deliberately slow.

Salting and Slow Hashes

A salt is a random value added to each password before hashing, so two users with the same password get different hashes. This defeats precomputed lookup tables. Purpose-built algorithms such as bcrypt, scrypt, and Argon2 combine salting with a tunable cost factor that makes each guess expensive. Most of them generate and store the salt inside the output automatically.

A Real Scenario

A small store hashed passwords with plain SHA-256 and no salt. After a leak, attackers ran the stolen hashes against a public wordlist and cracked most accounts within hours, because identical passwords produced identical hashes and each guess was instant. Migrating to bcrypt with a sensible cost factor changed the economics entirely: the same brute-force attempt would now take an impractical amount of time per password.

How to Implement It

Use a real password hash Prefer Argon2 or bcrypt through a maintained library. Do not build your own.
Let the library handle salt bcrypt and Argon2 create a unique salt per password automatically.
Tune the cost factor Set it as high as your server tolerates for a login, then revisit as hardware improves.
Store only the hash string The output already contains the algorithm, cost, and salt.
Compare using the library Use its verify function, which handles timing-safe comparison.

Common Mistakes and How to Fix Them

Using MD5 or SHA for passwords. They are too fast and crackable at scale. Fix: switch to bcrypt or Argon2.

Reusing one global salt. A shared salt lets attackers attack all accounts at once. Fix: use a unique per-password salt, which good libraries do for you.

Setting the cost factor too low. A tiny cost makes hashing cheap for attackers too. Fix: increase it until a login takes a fraction of a second, not microseconds.

Enforcing a low maximum length. Truncating passwords weakens them. Fix: allow long passphrases and do not silently cut them.

Logging the raw password. Debug logs can leak plain text. Fix: never log credential fields.

Action Checklist

  • Confirm no password is ever stored or logged in readable form.
  • Adopt Argon2 or bcrypt through a well-maintained library.
  • Rely on the library for per-password salting.
  • Set and periodically raise the cost factor.
  • Rehash a user’s password on next login when you upgrade the algorithm.
  • Add rate limiting on login to slow online guessing.

Conclusion

Never store what you do not need to keep. A one-way, salted, deliberately slow hash means a breach exposes gibberish instead of passwords. Next step: check what your login system stores today, and if it is anything reversible, plan a migration to bcrypt or Argon2.

FAQ

What is the difference between hashing and encryption?

Encryption is reversible with a key; hashing is one-way. Passwords should be hashed, because you never need to recover the original, only to verify it.

Do I need a salt if I use bcrypt?

bcrypt already generates and embeds a unique salt for you. You do not add one manually, but you should not disable it either.

Which algorithm should I choose today?

Argon2 is the modern recommendation, with bcrypt as a solid, widely supported alternative. Both are far better than any general-purpose hash.

How do I upgrade existing hashes safely?

You cannot rehash without the original password. Rehash each user’s password with the new algorithm the next time they log in successfully.

References

OWASP Password Storage Cheat Sheet, a well-known security guidance resource maintained by the Open Worldwide Application Security Project.