Cache-Timing Side-Channel Attacks
debt(d5/e3/b3/t9)
Closest to 'specialist tool catches it' (d5). The detection_hints list semgrep as the tool, which catches the pattern of == or === comparison of HMAC signatures and tokens. This is a specialist SAST tool, not a default linter or compiler error — a developer must deliberately configure and run semgrep to catch these comparisons. The cache-timing leak variant (response timing revealing cache hits) is harder still and likely d7, but the dominant == comparison pattern lands at d5.
Closest to 'simple parameterised fix' (e3). The quick_fix is to replace == with hash_equals() for security-sensitive comparisons — that's a targeted pattern replacement. Common mistakes show a consistent pattern: swap == for hash_equals(), use password_verify() instead of raw ==, use timing-safe base64 decoding. Each fix is a small, localised substitution within one file or function, not a cross-cutting architectural change. Slightly more than a one-liner (e1) because multiple call sites may need updating, but well within e3.
Closest to 'localised tax' (b3). The applies_to scope is web and api contexts, and the fix is a coding pattern (use hash_equals() consistently) rather than an architectural commitment. Once developers know the rule, enforcement is localised to security-sensitive comparison points. It doesn't reshape the whole codebase or impose a persistent productivity tax on unrelated work streams — it's a discipline applied at specific, identifiable spots.
Closest to 'catastrophic trap' (t9). The misconception field states exactly this: developers believe millisecond timing differences are too small to exploit, but statistical analysis over thousands of requests reveals sub-microsecond differences that make attacks practical even from the same data centre. The why_it_matters section confirms the 'obvious' approach (== comparison) is always wrong for security tokens — it leaks character-by-character prefix information. A competent developer who doesn't know this concept will almost certainly reach for == as the natural equality check, making this a catastrophic cognitive trap.
Also Known As
TL;DR
Explanation
Timing attacks exploit measurable differences in execution time to infer secrets. Cache timing: an attacker queries a resource and measures response time — a cache hit is faster than a miss, revealing whether the resource was recently accessed by another user. This leaks: whether a user exists (cached profile = faster response), whether a secret token was used, or whether a URL was recently visited. The classic timing attack is string comparison: == completes early on first mismatch, leaking how many characters were correct. Mitigations: hash_equals() for constant-time comparison, random delays, and careful cache key design.
Common Misconception
Why It Matters
Common Mistakes
- == for comparing HMAC signatures, CSRF tokens, or API keys — use hash_equals().
- Cache keys that include user IDs making timing leaks about user activity.
- Password comparison without timing safety — password_verify() is timing-safe, raw == is not.
- Not using constant-time base64 decoding for token comparison.
Code Examples
// Timing-vulnerable token comparison:
if ($submittedToken === $storedToken) { // Fails fast on first mismatch
// Attacker times thousands of requests:
// 'a...' takes 0.1ms — first char wrong
// 'sk1..' takes 0.3ms — first 3 chars right!
// Can brute-force character by character
allowAccess();
}
// Constant-time comparison — no timing information leaked:
if (hash_equals($storedToken, $submittedToken)) {
// Same time regardless of how many chars match
allowAccess();
}
// For HMAC verification:
$expected = hash_hmac('sha256', $payload, $secretKey);
if (!hash_equals($expected, $providedMac)) {
throw new InvalidSignatureException();
}
// password_verify() is also constant-time:
if (!password_verify($input, $storedHash)) {
throw new AuthenticationException();
}