const expected = crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
if (req.get("X-Signature") === expected) {
return handleWebhook(rawBody);
}
=== can stop at the first differing character and leak timing information; compare with crypto.timingSafeEqual on equal-length buffersThe weakness is the === comparison. A normal string comparison can stop at the first character that differs. So the response time can show how many of the first characters are correct. In principle, an attacker can use this to build a valid signature one piece at a time. This is a timing attack.crypto.timingSafeEqual takes the same time no matter where the difference is. But it throws an error when the two buffers have different lengths, so check the length first.
The other options are wrong:
• "HMAC-SHA256 is too weak for webhooks; use MD5 instead": HMAC-SHA256 is strong, and MD5 is weaker.
• "The signature must be compared in lowercase": the letter case is not the security problem.
• "digest("hex") makes the HMAC reversible": hex is only a way to write the bytes as text. It does not make the hash reversible.