Secure Coding Practices — Series 2

Preview — 3 of 10 questions

Which approach better protects a JWT session token against theft via XSS, and why?

javascript
// Option A
localStorage.setItem('token', jwt);

// Option B
// Server response header:
// Set-Cookie: token=<jwt>; HttpOnly; Secure; SameSite=Strict
ABoth are equally secure, since JWTs are already signed and cannot be tampered with regardless of storage location.
BOption B (an HttpOnly cookie), because JavaScript cannot read HttpOnly cookies at all — even if an XSS vulnerability exists elsewhere on the page, injected script cannot steal the token this way.
COption A (localStorage), because cookies are always sent to every domain, leaking the token to third parties.
DOption A (localStorage), because localStorage is encrypted by the browser automatically.

A regular user sends a PUT request with body { "name": "Alice", "isAdmin": true }. What is the vulnerability, and what's the fix?

javascript
app.put('/api/users/:id', (req, res) => {
  const updates = req.body; // e.g. { name: "Alice", isAdmin: true }
  db.updateUser(req.params.id, updates); // spreads all fields directly into the DB
  res.json({ success: true });
});
AThis is CSRF, since PUT requests are never protected by CSRF tokens.
BThis is SQL injection, caused by directly inserting req.body into a query string.
CThere is no vulnerability, since isAdmin is a boolean and booleans cannot be used to escalate privileges.
DThis is a mass assignment vulnerability — the endpoint blindly writes every field the client sends, including ones the client should never be able to control (like isAdmin); the fix is to explicitly whitelist only the fields a user is allowed to update (e.g., just name), rather than passing the entire request body through.

For comparing security-sensitive secrets (like API tokens or password-reset codes), why can a plain === comparison be a subtle security risk, even though it's functionally correct?

javascript
function isValidToken(input, expected) {
  return input === expected;
}
A=== is not functionally correct for comparing strings at all — it always returns false even for identical strings.
B=== comparisons throw a TypeError when comparing two strings, making this code always crash.
C=== string comparison in most engines can return as soon as it finds the first mismatched character, so the time it takes to return can vary based on how many leading characters match — in theory, letting a very patient attacker measuring response times guess a secret one character at a time. A constant-time comparison function avoids leaking this timing information.
DThere is no real risk in practice; timing attacks are purely theoretical and have never been demonstrated against real systems.

Sign up free to play

Answer all 10 questions (7 more), see explanations for every answer, and track your score.