·crypto
HMAC Lab
Key + message → tag. See the difference between naive `===` and constant-time tag comparison — why timing attacks are a real threat, visualised.
hmac · mac · timing-attack · sha-256
Key + message → tag. See the difference between naive `===` and constant-time tag comparison — why timing attacks are a real threat, visualised.
hmac · mac · timing-attack · sha-256
HMAC = Hash-based Message Authentication Code. Proves who sent a message — only someone with the key. Webhook signatures, API auth, the signature layer of JWTs, session tokens — all built on HMAC underneath.
Bad code:
function badEqual(a: string, b: string) {
if (a.length !== b.length) return false;
for (let i = 0; i < a.length; i++) {
if (a[i] !== b[i]) return false; // ← early return = timing leak
}
return true;
}An attacker can brute-force the tag character by character: a correct character makes the comparison run 1 ns longer. Over millions of requests the difference becomes statistically measurable.
The fix:
import { timingSafeEqual } from "node:crypto";
return timingSafeEqual(Buffer.from(a), Buffer.from(b));In the browser, crypto.subtle.verify() is already constant-time. But hand-rolled === comparison for webhook verification is a disaster.