Validating Webhook Payloads with SHA 256 Signatures
A webhook signature proves that the payload was created by a trusted sender and was not changed in transit. The server should compute the expected HMAC from the raw request body and compare it with the signature header safely.
A webhook signature proves that the payload was created by a trusted sender and was not changed in transit. The server should compute the expected HMAC from the raw request body and compare it with the signature header safely.
A webhook signature proves that the payload was created by a trusted sender and was not changed in transit. The server should compute the expected HMAC from the raw request body and compare it with the signature header safely.
Direct answer
Never trust a webhook just because it reaches your endpoint. Read the raw body, compute the expected HMAC using the shared secret, and compare it against the provider signature with a timing safe comparison.
After the signature is valid, use JSON Validator or JSON Formatter to inspect the payload during debugging. Do not validate formatted JSON as the signed body because formatting changes the byte sequence.
Python HMAC example
import hmac
import hashlib
def verify_signature(raw_body: bytes, secret: str, received_signature: str) -> bool:
expected = hmac.new(
secret.encode("utf-8"),
raw_body,
hashlib.sha256,
).hexdigest()
return hmac.compare_digest(expected, received_signature)
This function expects the raw request body exactly as received. If you parse and re serialize JSON first, the signature may not match.
Common mistake
# Wrong idea for signature validation
payload = request.json()
raw_body = json.dumps(payload).encode("utf-8")
This can change spaces, key order, and escaped characters. Use the raw body supplied by the web framework.
Django style approach
def webhook_view(request):
raw_body = request.body
received_signature = request.headers.get("X-Signature", "")
if not verify_signature(raw_body, settings.WEBHOOK_SECRET, received_signature):
return HttpResponse(status=401)
return HttpResponse(status=200)
Security checklist
- Use HTTPS for webhook endpoints.
- Verify the signature before trusting the payload.
- Use timing safe comparison.
- Reject old timestamps if the provider includes one.
- Log event IDs, not full sensitive payloads.
FAQ
Can I format webhook JSON before verifying it?
No. Verify the raw body first. Formatting changes the payload bytes and can break signature matching.
Is SHA 256 encryption?
No. SHA 256 is a hash function. HMAC with SHA 256 uses a secret key to authenticate the message.