Articles

What Is a Timing Attack? Side-Channel Leaks Explained

A timing attack infers secret data by measuring how long an operation takes to run. How timing side channels leak information and how to close them.

Chisato Chisato · · 4 min read
A padlock icon glowing red over a keyboard

A timing attack is a side-channel attack that infers secret information — a password, a cryptographic key, the existence of a username — by measuring how long an operation takes to complete rather than by breaking any encryption directly. If a comparison or lookup runs faster or slower depending on the secret data involved, the elapsed time itself becomes a leak, even when every byte the attacker actually receives is meaningless.

Why timing leaks anything at all

Most timing attacks exploit code that exits early on a mismatch. Consider a naive string comparison used to check an API key:

function isValid(input, secret) {
  if (input.length !== secret.length) return false;
  for (let i = 0; i < secret.length; i++) {
    if (input[i] !== secret[i]) return false; // exits on first mismatch
  }
  return true;
}

This looks correct, and functionally it is — it returns the right answer. But it returns wrong answers slower than right ones, character by character. A comparison against secret[0] being wrong fails almost instantly; a comparison that gets the first ten characters right before failing on the eleventh takes measurably longer, because the loop ran ten more iterations. An attacker who can send many requests and time the responses can brute-force the secret one character at a time — trying every possible next character and keeping whichever one makes the response take longest — instead of guessing the whole string at once. What would be an astronomically large search space becomes a linear one.

Where timing attacks show up in practice

  • String comparison for API keys, tokens, or HMAC signatures — the classic case above.
  • Password checks where early-exit comparisons leak how many leading characters were correct, though modern password hashing with bcrypt or Argon2 largely sidesteps this by hashing before comparing.
  • User enumeration — a login endpoint that checks “does this username exist” before “is this password correct” often responds faster for nonexistent usernames, letting an attacker map out valid accounts without ever guessing a password.
  • RSA and other public-key operations, where naive implementations of modular exponentiation take different numbers of steps depending on the bits of the private key. This is a large part of why cryptographic libraries are written and audited so carefully instead of implemented from scratch — see how digital signatures work for the broader context of why key-handling code carries this much scrutiny.
  • Padding oracle attacks, a related side channel where decryption error messages (or their timing) reveal whether padding was valid, letting an attacker decrypt ciphertext without the key.

None of these require intercepting network traffic or breaking math — they only require the ability to make repeated requests and measure response time precisely, which over a local network or against a server the attacker controls timing conditions for is often precise enough to matter.

Constant-time comparison

The standard defense is a constant-time comparison function — one whose running time does not depend on where or whether a mismatch occurs. Instead of returning as soon as a difference is found, it walks the entire input and accumulates the differences, only checking the accumulated result at the end:

function constantTimeEqual(a, b) {
  if (a.length !== b.length) return false;
  let diff = 0;
  for (let i = 0; i < a.length; i++) {
    diff |= a.charCodeAt(i) ^ b.charCodeAt(i);
  }
  return diff === 0;
}

Every call examines every character, whether the first byte matches or the string is identical — so elapsed time no longer correlates with how close the guess was. Most languages ship a built-in for this rather than expecting developers to write it by hand (Node’s crypto.timingSafeEqual, Python’s hmac.compare_digest, and equivalents elsewhere) — always prefer the standard library version, since subtle compiler optimizations can silently reintroduce a data-dependent shortcut into a hand-rolled loop.

Timing attacks vs other side-channel attacks

Timing attackPower analysisCache attack
Signal measuredResponse latencyElectrical power drawShared CPU cache access patterns
Typical targetNetwork services, string comparisonsSmart cards, embedded devicesCo-located processes, cloud VMs
Attacker access neededAbility to send requests and measure timePhysical or close proximityCode execution on the same host
Primary defenseConstant-time algorithmsPower-consumption randomizationCache partitioning, constant-time memory access

All three are side-channel attacks in the same family: they extract secrets from the implementation of a system rather than a weakness in the underlying cryptographic algorithm. A perfectly secure algorithm can still be broken by a leaky implementation.

What this means beyond comparison functions

Timing-safe design goes beyond string equality. Rate limiting, WAF rules, and generic error messages (“invalid username or password” rather than distinguishing the two cases) all reduce how much a timing or response-content difference can reveal. If you’re implementing authentication, prefer an established library or identity provider over custom comparison logic — the same advice that applies to JWT handling applies here: the concepts are simple, but the edge cases that make an implementation actually safe are not.

The takeaway

A timing attack turns response latency into a side channel, extracting secrets by measuring how long an operation takes rather than by breaking any cipher. Early-exit comparisons, naive password checks, and unguarded username-enumeration endpoints are the most common culprits. The fix is constant-time comparison — using your language’s built-in timing-safe equality function rather than a hand-rolled loop — plus generic error responses that don’t leak which part of a check failed.

Chisato Chisato · · 4 min read

OCSP vs CRL: How Certificate Revocation Works

OCSP and CRL are the two mechanisms browsers use to check if a TLS certificate has been revoked before its expiry date. Here's how each works.

#Security #Cryptography #Networking
Chisato Chisato · · 5 min read

IDS vs IPS: Intrusion Detection vs Prevention

An IDS watches network traffic and alerts on threats; an IPS sits inline and blocks them automatically. How the two compare and when to use each.

#Security #Networking #Web Development
Chisato Chisato · · 4 min read

What Is a Zero-Knowledge Proof?

A zero-knowledge proof lets one party prove a statement is true without revealing why — the basis of privacy-preserving verification systems.

#Security #Cryptography