đ The Modern Password Paradox
We live in an age where everything has to be instant: the site loads in 100âŻms, scrolling is smooth as butter, and users expect to be logged in before they even finish typing their email.
So, as developers, we obsess over reducing TTFB, we do cache acrobatics, and shave off milliseconds from response times like our professional dignity depended on it.
And then⊠there’s the login.
Thatâs the one place where your web or app should take its sweet time. And not because of laziness or sloppy code. Quite the opposite.
Sometimes, if your login is lightning fast, you should be hearing this in your head:
đš Wait⊠is this actually implemented correctly?
đš Are we hashing with something slow and secure like bcrypt or Argon2?
đš Or did someone get nostalgic and throw in a good ol’ MD5 from the 2000s?
Yep, hereâs the paradox: fast apps are great. But logins that are too fast can be a red flag. Because in the real world, a solid login needs to spend a few precious milliseconds (or even seconds) doing the dirty work: comparing hashes, salting passwords, and using intentionally slow hashing algorithms to fend off brute-force attacks.
It might annoy the impatient user, sure⊠But it could save you from a legendary mess.
The kind that ends in headlines or mass emails starting with âWe regret to inform you about a potential data breachâŠâ
Letâs break it down.
đ First Things First: How Should Passwords Be Stored? (Spoiler: they shouldnât.)
Letâs go back to basics â itâs never a bad idea: Passwords should never be stored.
Let me repeat: NE-VER STO-RED.
Not in the DB, not in a post-it, not in an env var, and for the love of tech gods, not in an Excel file on your desktop named clients_2025_FINAL_FINAL2.xlsx
.
â Donât store passwords. Period.
âOkay but⊠how the hell does the app know if the password is correct then?â
What gets stored is a hash. And no, thatâs not just a fancy new name for a password. Itâs something else entirely.
đ So, Whatâs a Hash?
A hash is the result of applying a mathematical function to a string (in this case, a password). The cool part?
- The same input always gives the same output.
- You canât reverse it. You can hash a password, but you can’t âunhashâ it (in theory â unless you’re the FBI with a quantum computer).
- Tiny changes in the input = totally different output.
Example:
hash("solodani123") â a21c8d4e5f4b7
âWait wait wait⊠so when I type my password, how does the app check itâs right?â
Easy.
In your database, youâll store this:
user | password_hash |
dani | a21c8d4e5f4b7 |
julieta | f8783hu7374nf |
When you type dani
and solodani123
in the login fields, the app hashes the password again, gets the same string, and compares it with the stored one.
If it matches: đ You’re in.
If it doesn’t: â Bye.
And all that without ever storing the real password. Neat, huh?
Well⊠thatâs just the beginning đ
đ€ âOkay but what do you mean it canât be reversed?â
Letâs illustrate this with a painfully realistic example:
Imagine your cousinâs kid is now a self-proclaimed developer and thinks heâs Linus Torvalds. Instead of using bcrypt like a normal human, he invents his own âsuper secureâ algorithm, because âif everyone knows how bcrypt works, it canât be safe.â
So he writes this:
function hash(password) {
let sum = 0;
for (let i = 0; i < password.length; i++) {
if (i % 2 === 0) {
sum += parseInt(password[i]);
}
}
return sum;
}
What it does: adds up the digits in even positions (assuming numeric passwords).
So:
Password | Even positions | Hash (sum of even positions) |
1111 | 1,1 | 2 |
1210 | 2,0 | 2 |
2193 | 1,3 | 4 |
Voilà . A unique, fast, simple hashing algorithm⊠as secure as a paper door.
Youâre starting to see the problem, right?
- Multiple passwords produce the same hash.
- Tons of info is lost in the process.
So even if someone steals your DB, they wonât get the actual passwords â just the hash. ButâŠ
Letâs test your cousin’s system:
If your type 1111
, you can log in. Great!
But guess what? You can also log in with 1210
.
And 2131
.
And 2121
.
And 3131
… and so on.
đ Thatâs why you donât roll your own crypto.
Not even after reading this post. Not even if youâre feeling clever in the shower.
Use bcrypt, scrypt, or Argon2. Theyâve been tested, reviewed, audited, and battle-hardened.
If someone tells you âbcrypt isnât safe because everyone knows how it works,â do this: Close your laptop, take a deep breath, revoke their prod access…
đŁ So How Do Passwords Get Cracked?
At its core, password cracking is pretty basic:
Grab a wordlist (aka âdictionaryâ) and test entries one by one.
If your user is one of those âmeh, Iâve got nothing to hideâ types who uses 123456
or password123
, itâs game over fast.
But if your password is one of the good ones â you know, with letters, numbers, uppercase, and those annoying special characters the system makes you add â itâll probably take them a lot longer.
And hereâs where a slow login saves your bacon.
Because bots â not humans â are testing those passwords. And bots are fast. Like really fast.
So if your login responds at the speed of light⊠Youâre basically inviting a brute-force fiesta. đ
đ The fix?
Add intentional delays. Yes. On purpose. Seriously.
And if that delay is random, even better. (It protects against timing attacks. More here.)
đŸ Wait⊠What Do Hashes Have to Do With It?
Ah! Youâve been paying attention. Nice.
Letâs walk further into this rabbit hole.
đ”ïžââïž How Attackers Might Hijack Your Users’ Facebook Accounts
Letâs say your site is booming with 1 million users.
In your DB you store this:
user | password_hash (MD5) |
soy@solodani.com | e10adc3949ba59abbe56e057f20f883e |
someone@gmail.com | 482c811da5d5b4bc6d497ffa98491e38 |
All good, right? You hashed the passwords. Relax.
ExceptâŠ
- You used MD5 (which is deader than Flash).
- You didnât use salts (more on this post đ The salt and pepper of passwords).
- Your server hasnât been updated in months. Because you’ll do “tomorrow”.
- Your DB password is still
changethis
from your.env
file.
What could go wrong? đ
Answer: everything.
Now a hacker â not even a smart one â gets access to your DB and grabs the user/password_hash table.
But hey, itâs hashed! All good! âŠRight?
đŹ Not so fast.
Go to đ https://md5decrypt.net
Paste in that hash (e10adc3949ba59abbe56e057f20f883e
) and hit âDecryptâ.
đ„ Boom.

Plain text password in seconds.
Now imagine your user reused that password on Facebook. Guess whoâs got access to their Facebook account?
đ± WTF! Arenât Hashes Supposed to Be Irreversible?
They are. I didnât lie. Promise.
But hackers arenât your cousinâs kid. Theyâre smart. Like, really smart.
They precompute hashes of millions of common passwords and match those against stolen hashes. Itâs called a rainbow table.
And since we humans are lazy and reuse passwords like maniacsâŠ
đ„ One breach = multiple accounts compromised.
đ Password Advice for Your Users
đ Never reuse passwords. If one site leaks your hash, youâre toast on every other site using the same password.
Use a password manager. You wonât remember 50 strong passwords. And post-its are not the answer.
Always enable 2FA. Itâll save your butt if your password gets leaked.
Stop using âverano2025â as your password.
Donât use security questions if the answer is on your Instagram.
âWhatâs my petâs name?â â your last 50 posts.
Check if your email was in a breach:
đ https://haveibeenpwned.com
Never share passwords via email.
Not your bank. Not Netflix. Not the Nigerian prince.
đ§âđ» Okay⊠So How Should You Build a Login?
Glad you asked. Hereâs your dev tattoo checklist (or README.md, your call):
đ Never store passwords. Store hashes.
And no, MD5 doesnât count. Neither does SHA1. SHA256 without salt? Still nope. Use bcrypt, scrypt, or Argon2.
Theyâre slow â and thatâs the whole point.
đ§ Always use salt.
A random salt, unique per user. That way, even if two people have the same password, the hashes will be different.
And rainbow tables? Let them go fry monkeys đ.
Yeah, yeah, I know â I havenât explained what salt is in a hash. But this post is already long enough. Iâm covering on this post đ The salt and pepper of passwords
đ¶ïž If you can, add pepper.
A secret value, fixed and stored outside the database (in your config, env file, etc).
Itâs just another little bump in the road for anyone who steals your DB.
Havenât explained this one either â itâs kinda like salt. More info đ The salt and pepper of passwords
đ« Donât invent your own hash algorithm.
Ever. Never. Not even if you came up with a âbrilliant ideaâ in the shower.
Stick to public, reviewed, audited, battle-tested algorithms.
đ§ Make the login process intentionally slow.
Yep, you read that right: add delays.
Donât let bots hammer your system with thousands of attempts per second. And if you can, make that delay random â protect yourself from timing attacks.
đ Apply 2FA if you can (and donât limit it to just admins).
Even if your login is Fort Knox, passwords can still get leaked on other sites with crappy security.
And when that happens, only 2FA stands between your users and disaster.
đ Log login attempts (but never the passwords).
You need traceability. Know if someone fails 20 times in 2 minutes.
But never log what password was tried. Never.
đ Apply rate-limiting on the login endpoint.
Yes, even if youâve got CAPTCHA.
Throttle by IP, by account, by cookie⊠whatever works. Just put a limit.
đ Never leak extra info in error messages.
Saying âUser not foundâ or âIncorrect passwordâ helps attackers a lot.
Stick with a generic error: âInvalid credentials.â Full stop.
đ§Ș Test your login like youâre trying to break it.
Try weird passwords, emojis, injection attemptsâŠ
If youâre not trying to break it, someone else will.
đ€ Add CAPTCHA (but use your head)
It wonât save you from everything, but it slows down dumb bots that blindly hammer your login form.
- Use it after a few failed attempts, so you donât ruin the UX from the start.
- If possible, use reCAPTCHA v3 or something invisible â less friction, same effect.
- If itâs a visible one, make sure it works on mobile and isnât a UX nightmare.
CAPTCHA wonât stop the pros, but itâs a decent trap to catch the clumsy ones.
So, what do you think ?