Timing Attacks Explained

TL;DR

Timing attacks pull secret data out of how long an operation takes to run. The tell: === string comparison exits the moment it hits a mismatch, so a guess that matches more characters takes a hair longer to fail. That's the leak. Use a constant-time comparison like crypto.timingSafeEqual anywhere you're checking secrets, tokens, or passwords.

How Timing Attacks Work

Vulnerable: early-exit comparison
// JavaScript === returns immediately on first difference
function checkApiKey(provided, actual) {
  return provided === actual;  // VULNERABLE!
}

// If actual = "secret123"
// "axxxxxxxx" - fails immediately (fast)
// "sxxxxxxxx" - first char matches, then fails (slightly slower)
// "sexxxxxxx" - two chars match (even slower)

// By measuring response times, attacker can guess one char at a time

What Can Be Leaked

  • API keys and tokens
  • Password hashes (comparing to stored hash)
  • HMAC signatures
  • Session tokens
  • Any secret comparison

The Fix: Constant-Time Comparison

Safe: using crypto.timingSafeEqual
import crypto from 'crypto';

function safeCompare(a, b) {
  // Must be same length for timingSafeEqual
  if (a.length !== b.length) {
    return false;
  }

  return crypto.timingSafeEqual(
    Buffer.from(a),
    Buffer.from(b)
  );
}

// This always takes the same time regardless of where they differ

Length-Safe Version

Hiding length differences
function constantTimeCompare(provided, actual) {
  // Use HMAC to normalize length
  const hash = (s) => crypto
    .createHmac('sha256', 'constant-key')
    .update(s)
    .digest();

  return crypto.timingSafeEqual(
    hash(provided),
    hash(actual)
  );
}

Is this attack practical over the network?

Over a local network, yes. Further out, still yes with enough samples: statistical analysis picks up timing differences down to microseconds. CDNs and cloud routing add noise, but noise isn't the same as safety.

Does bcrypt prevent this for passwords?

Bcrypt handles password storage. It doesn't automatically make the hash comparison constant-time, that's what bcrypt.compare() does under the hood, so use it instead of comparing hashes yourself.

Find Timing Vulnerabilities

Our scanner identifies timing-unsafe comparisons in your code.

Vulnerability Guides

Timing Attacks Explained