Skip to main content

Free 30-min security demo  — We'll scan your real code and show live findings, no commitment Book Now

Offensive360
Academy Timing Side-Channel Attacks
Advanced · 20 min

Timing Side-Channel Attacks

Understand how response time differences leak secret data and how constant-time comparison stops them.

1 Timing Attack Mechanics

A timing side-channel attack exploits the fact that standard string comparison functions return early when they find a mismatch — the more matching characters, the longer the comparison takes. An attacker who can measure response time can infer secret values one character at a time.

Vulnerable HMAC verification (Python):

def verify_token(user_token, expected_token):
    # == does early exit: stops at first mismatch
    return user_token == expected_token
    # If user sends "aXXXXXXXX..." and the real token starts with "a",
    # the comparison takes slightly longer — the "a" matches!

Attack scenario: An attacker sends thousands of API webhook requests with different HMAC signature values. By measuring response times statistically, they can determine the correct signature byte-by-byte without knowing the secret.

This requires very precise timing measurements, but network timing attacks have been demonstrated in practice with enough requests to average out noise.

2 Constant-Time Comparison

The fix is to use comparison functions specifically designed to take the same amount of time regardless of where the first mismatch occurs.

Python — hmac.compare_digest:

import hmac

def verify_token(user_token, expected_token):
    # compare_digest always compares all bytes, regardless of mismatch position
    return hmac.compare_digest(
        user_token.encode("utf-8"),
        expected_token.encode("utf-8")
    )

Node.js — crypto.timingSafeEqual:

const crypto = require("crypto");

function verifyHMAC(userSig, expectedSig) {
  const a = Buffer.from(userSig, "hex");
  const b = Buffer.from(expectedSig, "hex");
  // Buffers must be same length for timingSafeEqual
  if (a.length !== b.length) return false;
  return crypto.timingSafeEqual(a, b);
}

Defense checklist:

  • Use hmac.compare_digest (Python) or crypto.timingSafeEqual (Node.js) for all secret comparisons
  • Never use == or === for comparing HMACs, tokens, or passwords
  • Ensure buffers are same length before comparing (length itself can leak info)
  • Use bcrypt.checkpw for password verification (built-in constant time)

Knowledge Check

0/3 correct
Q1

How does a timing attack determine a secret value one character at a time?

Q2

Which Python function provides timing-safe string comparison?

Q3

When comparing two buffers with crypto.timingSafeEqual in Node.js, what must you check first?

Code Exercise

Use Constant-Time Comparison

The HMAC verification uses == which is vulnerable to timing attacks. Replace it with hmac.compare_digest for constant-time comparison.

python