Facebook Pixel

Common Password Hashing Mistakes (and How to Avoid Them)

Hashing passwords wrong defeats the purpose. Here are common mistakes and fixes.

Common Password Hashing Mistakes

Hashing passwords wrong defeats the purpose. Here are common mistakes and how to avoid them.

Mistake 1: Storing Passwords in Plain Text

The worst mistake. A database leak exposes every user. Fix: hash with bcrypt or argon2 before saving. Always.

Mistake 2: Using a Fast Hash Like SHA-256

SHA-256 is fast, so brute-forcing a list of hashes is fast. Fix: use a slow password hash (bcrypt, argon2, scrypt). They are slow on purpose.

Mistake 3: No Salt

Without a salt, two users with the same password get the same hash. Attackers can use rainbow tables. Fix: bcrypt and argon2 handle salting automatically. Do not roll your own.

Mistake 4: Low Salt Rounds

bcrypt with 5 rounds is too fast. An attacker can brute-force quickly. Fix: use 10 or 12 rounds. 10 is fine for most apps; 12 for high-security.

Mistake 5: Hashing Sync in Request Handlers

bcrypt.hashSync blocks the event loop. Other requests stall. Fix: use the async API (await bcrypt.hash). Use async/await in a pre('save') hook.

Mistake 6: Returning passwordHash in Responses

You send the hash to the client. Even hashed, it should not leave the server. Fix: mark passwordHash with select: false. Use a serializer that omits it.

Mistake 7: Logging Passwords or Hashes

A debug log accidentally contains the password. Fix: never log passwords or hashes. Filter them from logs. Use a logger that redacts known sensitive fields.

Mistake 8: Rehashing on Every Save

You hash in pre('save') without checking if the password changed. Profile updates rehash the existing hash, breaking login. Fix: check this.isModified('passwordHash') before hashing.

Mistake 9: Not Handling Updates

findByIdAndUpdate bypasses pre('save'). The new password is stored unhashed. Fix: hash in a pre('findOneAndUpdate') hook, or hash in the controller before calling update.

Mistake 10: Using the Same Hash for Different Purposes

You use the password hash for an API token too. Fix: use different hashes for different purposes. JWT for tokens, bcrypt for passwords. Never mix.

The Takeaway

Common password hashing mistakes: plain text, fast hashes (SHA-256), no salt, low rounds, sync hashing, returning hashes, logging hashes, rehashing on every save, not handling updates, and mixing purposes. Fix them on day one.

Plain text, fast hashes (SHA-256), no salt, low rounds, sync hashing in request handlers, returning passwordHash in responses, logging passwords or hashes, rehashing on every save, not handling updates, and mixing purposes.

It is a fast hash, not a password hash. Fast means brute-forcing a list of hashes is fast. Password hashes (bcrypt, argon2) are slow on purpose, which makes brute-force expensive.

It blocks the event loop. Other requests stall while the hash runs. Use the async API (await bcrypt.hash). In Mongoose, use a pre('save') hook with async/await.

Without the check, every save rehashes the existing hash. Profile updates would rehash the already-hashed password, breaking login. Use if (!this.isModified('passwordHash')) return next();

Logs are often shipped to centralized systems with broader access than the database. A password or hash in logs is a leak waiting to happen. Filter sensitive fields from logs or use a logger that redacts them.

Ready to master Node.js completely?

Want to upskill yourself, crack your next interview, and get your dream job? Join our comprehensive course to dive deeper with high-quality video tutorials, solve interview questions, and a premium community.

Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.
Please Login.