Preventing Timing Attacks
1. Understanding Timing Attack Vectors
| Vector | Leak |
|---|---|
| String compare (==) | Returns early on mismatch — reveals prefix |
| User existence | Different response times for valid vs invalid user |
| Cache hits | Faster response reveals state |
| DB query | Index hit vs miss |
2. Implementing Constant-Time Comparisons
Example: Per-language API
Node: crypto.timingSafeEqual(a, b) // equal-length Buffers
Python: hmac.compare_digest(a, b)
Go: subtle.ConstantTimeCompare(a, b) == 1
Java: MessageDigest.isEqual(a, b)
Ruby: ActiveSupport::SecurityUtils.secure_compare
3. Using Secure String Comparison
Warning: Even constant-time compare leaks length. Hash both sides (HMAC with random key) before compare to mask length.
4. Handling Username Enumeration
| Endpoint | Mitigation |
|---|---|
| Login | Same error for unknown user vs wrong password |
| Signup | Generic "If account exists, check email" |
| Password reset | Always respond 200; send email only if exists |
| Timing | Hash dummy password even when user not found |
5. Implementing Consistent Response Times
Example: Pad to fixed minimum
async function login(email, pw) {
const start = Date.now();
const user = await User.findByEmail(email);
const hash = user?.passwordHash ?? "$argon2id$v=19$m=65536,t=3,p=4$xxxxxx";
const ok = await argon2.verify(hash, pw);
// Pad to min 300ms
const elapsed = Date.now() - start;
if (elapsed < 300) await new Promise(r => setTimeout(r, 300 - elapsed));
return ok && user;
}
6. Using Dummy Operations
Perform equivalent CPU work (e.g., dummy hash) when account does not exist so request timing is indistinguishable.
7. Handling Cache Timing Attacks
| Mitigation | Detail |
|---|---|
| Cache by category | Same cache key class for valid/invalid |
| Random delay | Add jitter to mask cache hits |
| Pre-warm | Avoid cold-vs-warm signal |
8. Implementing Response Time Randomization
Warning: Random delay alone is statistically defeatable. Combine with constant-time + dummy ops.
9. Using Rate Limiting to Mask Timing
Aggressive per-IP rate limits prevent attacker from collecting enough samples to extract a timing signal.
10. Preventing Information Leakage
| Source | Mitigation |
|---|---|
| Error messages | Generic, identical for similar failures |
| HTTP status | Same code (e.g., always 401, never 404) |
| Response size | Pad responses |
| Logs | Don't echo sensitive input |