{"title":"Timing Attack via hmac.compare_digest Misuse","language":"Python","severity":"High","cwe":"CWE-208","source_lines":[7],"flow_lines":[6,7,8],"sink_lines":[8],"vulnerable_code":"import hmac\nimport hashlib\nfrom flask import request, jsonify\n\ndef verify_iot_device_signature(device_id, payload, signature):\n    secret_key = get_device_secret(device_id)\n    expected_sig = hashlib.sha256(f\"{device_id}:{payload}:{secret_key}\".encode()).hexdigest()\n    if signature == expected_sig:\n        return jsonify({\"status\": \"authenticated\", \"device_id\": device_id})\n    return jsonify({\"status\": \"unauthorized\"}), 401\n\n@app.route('/iot/telemetry', methods=['POST'])\ndef receive_telemetry():\n    dev_id = request.headers.get('X-Device-ID')\n    sig = request.headers.get('X-Signature')\n    data = request.get_json()\n    return verify_iot_device_signature(dev_id, data.get('payload'), sig)","explanation":"The code uses string equality comparison (==) instead of constant-time comparison (hmac.compare_digest) to verify signatures. This allows attackers to perform timing attacks by measuring response times to determine correct signature bytes one at a time, eventually reconstructing valid signatures without knowing the secret key.","remediation":"The fix replaces the vulnerable string equality comparison (==) with hmac.compare_digest(), which performs constant-time comparison to prevent timing attacks. Additionally, the signature computation was changed from a plain SHA-256 hash (which included the secret in the message) to a proper HMAC construction using hmac.new(), which is the cryptographically correct way to create keyed message authentication codes. Input validation was also added to prevent NoneType errors.","secure_code":"import hmac\nimport hashlib\nfrom flask import request, jsonify\n\ndef verify_iot_device_signature(device_id, payload, signature):\n    secret_key = get_device_secret(device_id)\n    expected_sig = hmac.new(secret_key.encode(), f\"{device_id}:{payload}\".encode(), hashlib.sha256).hexdigest()\n    if hmac.compare_digest(signature, expected_sig):\n        return jsonify({\"status\": \"authenticated\", \"device_id\": device_id})\n    return jsonify({\"status\": \"unauthorized\"}), 401\n\n@app.route('/iot/telemetry', methods=['POST'])\ndef receive_telemetry():\n    dev_id = request.headers.get('X-Device-ID')\n    sig = request.headers.get('X-Signature')\n    if not dev_id or not sig:\n        return jsonify({\"status\": \"unauthorized\"}), 401\n    data = request.get_json()\n    if not data or not data.get('payload'):\n        return jsonify({\"status\": \"bad_request\"}), 400\n    return verify_iot_device_signature(dev_id, data.get('payload'), sig)"}