Predict the output
The receiver verifies once over the raw bytes and once after parsing and re-encoding the JSON. What prints?
import hashlib
import hmac
import json
SECRET = b"whsec_demo"
def signature(ts: int, body: bytes) -> str:
msg = str(ts).encode() + b"." + body
return hmac.new(SECRET, msg, hashlib.sha256).hexdigest()
ts = 1767225600
raw = b'{"event":"paid","id":"evt_1"}'
sig = signature(ts, raw) # what the sender put in the header
reencoded = json.dumps(json.loads(raw)).encode()
print(hmac.compare_digest(signature(ts, raw), sig))
print(hmac.compare_digest(signature(ts, reencoded), sig))
print(reencoded.decode())Hint 1 of 1
Does json.dumps write the same bytes the sender sent?
Choose an answer, then open Show answer below to check it.
Show answer
Answer: A True, False, then the body with spaces after : and ,
Correct. json.dumps adds spaces by default, so the re-encoded bytes differ from what was signed.
An HMAC covers exact bytes. Parsing and re-encoding JSON can change spacing, key order or escapes, so verify over the raw request body before you parse it.
Why not the others?
- B
True,True, then the body unchanged. Parsing and re-encoding doesn't give back the same bytes; json.dumps uses its own separators. - C
False,False, then the body unchanged. The first check uses the exact bytes that were signed, so it passes. - D
True,True, then the body with spaces. Any byte change, even a space, gives a different HMAC.