Don't Hash Trash
Hashing is one of those tools that feels like magic the first time you understand it, and dangerous the first time you see it used badly. This is a quick tour of what hashing is, why salts exist, and a story about a passwordless login system that you could quietly predict your way into.
What is hashing?
Hashing means passing data through a mathematical formula to produce a result — the hash. The important property is that it's one-way: you can hash data to create a hash, but you can't reverse a hash to recreate the original data. Common algorithms you'll have seen include md5, sha1 and bcrypt.
In a security context, hashing is most often used to protect user passwords. Rather than storing passwords in plain text — where they're exposed to anyone with database access, from administrators to attackers — you store only the hash. Even if the database is breached, the original passwords aren't sitting there waiting to be read.
Rainbow tables and salts
The catch is that the same input always produces the same hash. That predictability is what makes rainbow tables dangerous: enormous precomputed lookup tables that map hashes back to the values that produced them. If an attacker finds a stored hash of 25d55ad283aa400af464c76d713c07ad, a rainbow table will happily tell them the password was 12345678.
The defence is a salt: random data added to the input before hashing. Give every user a unique salt and identical passwords no longer produce identical hashes. Precomputed tables become useless, because the attacker would need a separate table for every salt. They're forced to crack each password individually instead of looking them all up at once.
How hashing practices have evolved
Early PHP code leaned on md5 and sha1. As computing power grew — especially cheap, massively parallel GPU power — those algorithms became fast enough to brute-force. Modern PHP gives you password_hash() and password_verify(), which generate a random salt for you and let you turn up the computational cost over time as hardware keeps improving. That adjustable cost is the whole point: a good password hash is deliberately slow.
How to hash badly
Here's where it gets fun. I once came across a passwordless authentication system that generated login pins by hashing the user's email address together with a sequential request identifier.
The problem: the identifier was predictable and simply incremented with each request. Because the input was guessable, an attacker could build their own local rainbow table, watch the pattern across a few login attempts, and then predict future pins for other users. The hashing was technically present — and completely worthless, because the thing being hashed had no real randomness in it.
The takeaway
Hashing protects you only when it's implemented correctly. The algorithm matters, but how you use it matters just as much:
- Don't roll your own authentication. Lean on established services like AWS Cognito or Auth0.
- When you need randomness, use a cryptographically secure generator — never a plain
rand(). - Remember that a hash is only as unpredictable as its input.
Good hashing isn't about reaching for the fanciest algorithm. It's about not hashing trash.