Timing-Safe Comparison: Side-Channel Defense
Strict equality stops at the first wrong byte and leaks timing information. timingSafeEqual runs constant time. Hash first, then compare.
Strict equality stops at the first mismatched byte. Response time reveals how many bytes matched.
Vulnerable:
if (credentials === expectedToken) { ... }
Safe:
import { createHash, timingSafeEqual } from 'node:crypto';
const digest = (v) => createHash('sha256').update(v).digest();
const safeEqual = (a, b) =>
timingSafeEqual(digest(a), digest(b));
Hashing first produces fixed-length buffers. timingSafeEqual requires equal length on both sides. The hash also prevents an early exit on length mismatch.
This pattern applies to: API key comparison, webhook signature verification, token matching, HMAC digest comparison.
Warning: The comparison function is one layer. Rate limiting and consistent auth paths complete the defense.
From the audit: game-server’s
authenticateCredentialsused strict equality for credential comparison. After the fix, it usescrypto.timingSafeEqual.
“Time is information. Constant-time comparison turns time into noise.”
References:
Related: back to the Seven Blind Spots Behind a JWT Audit overview · Six Standard Claims