# HMAC Verification Timing Attack via `==` String Comparison

Language: Python
Severity: High
CWE: CWE-208

## Source
7

## Flow
7-8

## Sink
8

## Vulnerable Code
```python
import hmac
import hashlib
from flask import request, jsonify

def verify_iot_device_command(device_id, command_payload, signature_header):
    device_secret = get_device_secret_key(device_id)
    expected_sig = hmac.new(device_secret.encode(), command_payload.encode(), hashlib.sha256).hexdigest()
    if signature_header == expected_sig:
        execute_device_command(device_id, command_payload)
        return jsonify({"status": "executed", "device": device_id})
    return jsonify({"error": "invalid signature"}), 403

def get_device_secret_key(dev_id):
    return f"iot_secret_{dev_id}_key"

def execute_device_command(dev_id, cmd):
    pass
```

## Explanation

The code uses a direct string comparison (`==`) to verify HMAC signatures instead of a constant-time comparison function. This allows attackers to perform timing attacks by measuring response times to determine each correct byte of the signature sequentially, eventually forging valid signatures to execute arbitrary device commands.

## Remediation

The fix replaces the vulnerable `==` string comparison with `hmac.compare_digest()`, which performs a constant-time comparison that takes the same amount of time regardless of how many bytes match. This prevents attackers from using timing side-channels to incrementally determine the correct signature byte-by-byte.

## Secure Code
```python
import hmac
import hashlib
from flask import request, jsonify

def verify_iot_device_command(device_id, command_payload, signature_header):
    device_secret = get_device_secret_key(device_id)
    expected_sig = hmac.new(device_secret.encode(), command_payload.encode(), hashlib.sha256).hexdigest()
    if hmac.compare_digest(signature_header, expected_sig):
        execute_device_command(device_id, command_payload)
        return jsonify({"status": "executed", "device": device_id})
    return jsonify({"error": "invalid signature"}), 403

def get_device_secret_key(dev_id):
    return f"iot_secret_{dev_id}_key"

def execute_device_command(dev_id, cmd):
    pass
```
