DEV Community

Piyush Bhadane
Piyush Bhadane

Posted on

Web Dev Cybersecurity: Securing Login Flows Beyond ZAP’s Reach.

Overview

Web developers these days create beautiful user interfaces, user experiences, and protect users' data against hackers and penetration testers. For example, if an application isn’t built with proper security controls, then tools such as OWASP ZAP can sit in the middle, intercept HTTP traffic, and reveal private credentials such as usernames and passwords.

So, how do developers ensure that even if ZAP is in the middle it doesn’t see plain credentials?
Let’s break it down.

Backend Protection: Hashing with bcrypt (or argon2)

Passwords should never be stored as plain text on the backend. Rather, a hashing library should be used, for example:

  • bcrypt (using bcryptjs in Node.js)
  • argon2 (this can be used with the argon2 npm package and offers stronger protection against GPU attacks) Example (Node.js API):
import bcrypt from 'bcryptjs';
const saltRounds = 12;

// Hash before storing
const hashedPassword = await bcrypt.hash('user-password', saltRounds);

// Later, verify login
const isMatch = await bcrypt.compare('user-password', hashedPassword);
console.log(isMatch ? 'Password valid' : 'Invalid login');
Enter fullscreen mode Exit fullscreen mode

Important: This runs on the backend API only, never in the frontend (React).

Transport Protection: Hiding Credentials from ZAP

Even if you hash on your backend, if you transmit passwords in plain text over HTTP, ZAP will see them. To prevent this, developers will need to configure the transport layer.

  1. Never Serve Over HTTP (Use HTTPS Everywhere)

Always serve your site over TLS/SSL. This protocol encrypts traffic between the client ↔ server, so ZAP (without certificate injection) will never see your credentials.
Libraries/Tools:
*helmet (an express middleware to add security headers)
*Free SSL using Let’s Encrypt

  1. Token-Based Authentication (JWT, OAuth2)

Instead of repeating username & password, issue a token after login.

  • First login: user sends credentials once (over HTTPS).
  • Server issues a JWT (JSON Web Token).
  • For every next request, client will send just the token.

Libraries/Tools:

  • jsonwebtoken (Node.js)
  • passport-jwt for Express/NestJS.
  1. Client-Side Encryption (optional for higher-security applications)

Some high-security applications (like banking) will take the password and encrypt it in the frontend before sending it.

  • Frontend encrypts password with RSA public key.
  • Backend decrypts with RSA private key and then bcrypt-hashes it.
  • ZAP will just see an encrypted blob.

Libraries/Tools:

  • node-forge (RSA encryption in JS)
  • crypto (Node.js built-in).
  1. Passwordless Authentication (No Password in Transit)

Recent applications don’t bother with passwords at all with WebAuthn / FIDO2.
Rather than sending a credential to the browser, it instead generates a cryptographic proof.
Nothing sensitive ever crosses the wire.

Libraries/Tools:
*@simplewebauthn/browser + @simplewebauthn/server
*It supports biometric login, security keys (YubiKey), etc.

Putting It All Together: Secure Login Flow

  1. Frontend (React) → A user enters in their credentials → Send it over HTTPS

  2. Backend (Node.js API) → Asynchronous hash of the password using bcrypt/argon2 before storing.

  3. Tokenization → Return a JWT instead of exposing the password again.

  4. Optional hardening → Add client-side encryption (RSA) or go passwordless (WebAuthn).

Tester’s Perspective (via ZAP)

  1. Unsecure: ZAP sees username=alice&password=12345.
  2. Secure with HTTPS + JWT: ZAP sees an encrypted request with tokens, no plain text passwords to see.
  3. The same for WebAuthn: ZAP sees cryptographic proofs... never credentials.

Conclusion

  1. Web dev + Cyber security = Thinking outside of UI.
  2. Use bcrypt/argon2 in the back.
  3. Use HTTPS.
  4. Use tokens rather than passwords.
  5. Use WebAuthn/FIDO2 for future-proof security.

Then, even if ZAP is in the middle, the secrets remain safe for your users.

Top comments (0)