{"title":"Timing Attack via Non-Constant-Time String Comparison in HMAC Authentication","language":"Python","severity":"High","cwe":"CWE-208","source_lines":[4],"flow_lines":[4,5],"sink_lines":[5],"vulnerable_code":"import hmac, hashlib\ndef verify_iot_device_token(dev_id, provided_sig, payload, secret_key):\n    raw = f\"{dev_id}:{payload}\".encode()\n    expected_mac = hmac.new(secret_key.encode(), raw, hashlib.sha256).hexdigest()\n    if provided_sig == expected_mac:\n        return {\"status\": \"authorized\", \"device\": dev_id}\n    return {\"status\": \"denied\"}","explanation":"The HMAC signature is computed on line 4 using hmac.new(), but compared on line 5 using Python's built-in == operator, which performs a short-circuit lexicographic comparison. This leaks timing information: comparisons fail faster when early bytes differ, allowing an attacker to brute-force the HMAC value byte-by-byte by measuring response times. The fix is to use hmac.compare_digest() instead of ==.","remediation":"The fix replaces the Python == operator on line 5 with hmac.compare_digest(), which performs a constant-time comparison of the two strings. This ensures that the comparison always takes the same amount of time regardless of how many bytes match, preventing an attacker from using timing side-channel analysis to brute-force the HMAC signature byte-by-byte.","secure_code":"import hmac, hashlib\ndef verify_iot_device_token(dev_id, provided_sig, payload, secret_key):\n    raw = f\"{dev_id}:{payload}\".encode()\n    expected_mac = hmac.new(secret_key.encode(), raw, hashlib.sha256).hexdigest()\n    if hmac.compare_digest(provided_sig, expected_mac):\n        return {\"status\": \"authorized\", \"device\": dev_id}\n    return {\"status\": \"denied\"}"}