Skip to solution
easyPhone Screen

How can you securely store and verify passwords in a Node.js application?

340 views
01

Understand the problem

Question presented to candidate: "A teammate suggests encrypting passwords with AES before storing them in the database, so they can be decrypted later if needed. What is wrong with that approach, and what should be done instead?"

What a strong answer should cover:

  • Passwords should never be stored in plain text, and — the specific mistake in the prompt — should never be stored encrypted (reversibly) either. A password should be hashed with a purpose-built, one-way, slow algorithm: the application should never be able to recover the original password, only verify a guess against the stored hash.
  • 📌 Salting is mandatory, not optional: a random, unique salt per password ensures that two users with the identical password produce completely different stored hashes — defending against precomputed rainbow-table attacks and revealing nothing about password reuse across accounts, verifiably, not just in theory.
  • The hashing algorithm must be deliberately slow and memory-hard — general-purpose fast hashes (MD5, SHA-256 used alone) are the wrong tool specifically because they are fast, which makes brute-forcing millions of guesses per second on stolen hashes cheap. Purpose-built choices: bcrypt, scrypt (available in Node's built-in crypto module, no external package needed), or Argon2 (the current, widely recommended default for new systems).
  • Comparing a supplied password's hash against the stored hash should use a constant-time comparison (crypto.timingSafeEqual), not a naive ===/Buffer.compare, to avoid leaking timing information about how many leading bytes matched.
  • A precise answer separates hashing algorithm choice from application-level concerns that matter just as much in practice: rate-limiting login attempts, never logging raw passwords, and using HTTPS so the password is not exposed in transit before it ever reaches the hashing step.
  • crypto.scrypt/scryptSync are genuinely built into Node with no external dependency required, which is worth naming precisely — many engineers assume secure password hashing always requires installing bcrypt.

Clarifying questions expected:

  • "Is this for a new system, or auditing an existing one that might already use a weak algorithm?" — decides between "pick a good algorithm" and "plan a migration."
  • "Does the interviewer want the hashing mechanism specifically, or the broader set of related practices (rate limiting, transport security)?"

Code / implementation expected: Yes — a real, working hash-and-verify pair (using Node's built-in crypto.scrypt, demonstrating both the salting property and constant-time comparison) is the concrete, convincing deliverable here.

securitycryptoauth
02

Attempt it yourself

Sketch your approach before reading the solution — that's what interviews test.

Nudge consolestandby

Stuck? Beam a request up — the console returns a conceptual nudge that guides your logic without spoiling the implementation.

03

Study the solution

Target Audience: Engineers preparing for Node.js security-focused phone screens — assumes very basic hashing familiarity. Difficulty: Easy

How to read this doc: Concepts are explained in plain language first, then tagged with 📌 Interview term:. The hash/verify pair below was *actually run

Solution ready — 2 min read

Classified // press E to declassify

04

Read the code

A real, built-in-only password hash-and-verify pair, verifying correctness, rejection, and per-password random salting
const crypto = require("crypto");

function hashPassword(password) {
  const salt = crypto.randomBytes(16).toString("hex");
  const hash = crypto.scryptSync(password, salt, 64).toString("hex");
  return `${salt}:${hash}`;
}

function verifyPassword(password, stored) {
  const [salt, hash] = stored.split(":");
  const candidate = crypto.scryptSync(password, salt, 64).toString("hex");
  return crypto.timingSafeEqual(Buffer.from(hash, "hex"), Buffer.from(candidate, "hex"));
}

const stored = hashPassword("correct-horse-battery-staple");
console.log(verifyPassword("correct-horse-battery-staple", stored)); // true
console.log(verifyPassword("wrong-password", stored));                // false

const s1 = hashPassword("samepassword");
const s2 = hashPassword("samepassword");
console.log(s1 !== s2); // true — different random salt each time, same password
05

Join the discussion

Discussion (0)

Sign in to join the discussion.

No responses yet. Be the first to share what you think.

Transmission complete // awaiting log

KEEP THE
STREAK ALIVE.

Dossier 25 of 152 decoded in the Node.js track. One more won't hurt.

Back to track