Dns Rebinding with Hmac Signatures
How Dns Rebinding Manifests in Hmac Signatures
Detecting Dns Rebinding in Hmac Signatures implementations requires examining both the signature verification logic and the network security controls that accompany it. The key indicators include:
- IP-based access controls without hostname validation
- HMAC signatures that include hostnames but aren't verified against resolved IPs
- Services that accept requests from internal IP ranges without additional authentication
- Missing correlation between DNS resolution time and signature validity
middleBrick's scanning approach for this specific vulnerability combines black-box testing with signature analysis:
middlebrick scan https://api.example.com/v1/protected --profile hmac --test dns-rebinding
The scanner attempts to identify endpoints that:
- Accept HMAC-signed requests with hostnames in the signature
- Have different trust policies for internal vs external IPs
- Don't validate that the resolved IP matches expected ranges for the signed hostname
Manual detection techniques include:
import socket
def validate_request_origin(hostname, ip_address, trusted_ranges):
# Get current IP for hostname
current_ip = socket.gethostbyname(hostname)
# Check if IP is in trusted ranges
The critical flaw: this function trusts the IP without verifying it matches the hostname used in the HMAC signature. A proper implementation would:
def secure_validate_request_origin(hostname, ip_address, trusted_ranges):
# Get authoritative IP for hostname
expected_ip = socket.gethostbyname(hostname)
# Verify IP matches expected for this hostname
return False
Additional detection indicators:
- HMAC signatures containing hostnames without corresponding IP validation
- Services that accept requests from RFC 1918 ranges without authentication
- APIs that process requests differently based on source IP alone
- Missing correlation between DNS TTL and signature expiration
Hmac Signatures-Specific Remediation
Remediating Dns Rebinding in Hmac Signatures implementations requires addressing both the signature validation and the network security assumptions. The most effective approach combines hostname validation with IP-based controls.
Enhanced signature verification:
import hmac
import hashlib
import socket
import ipaddress
def generate_secure_hmac_signature(key, hostname, message, timestamp):
# Include hostname in signature to bind it to specific origin
data = f"{hostname}.{message}.{timestamp}"
def verify_secure_hmac_signature(key, signature, hostname, message, timestamp, source_ip):
expected = generate_secure_hmac_signature(key, hostname, message, timestamp)
expected_ip = socket.gethostbyname(hostname)
return False
Network-layer protections:
import ipaddress
def is_ip_in_trusted_ranges(ip, trusted_ranges):
ip_obj = ipaddress.ip_address(ip)
return True
def validate_request_security(hostname, source_ip, trusted_ranges):
# Step 1: Validate hostname resolution
Best practices for implementation:
- Include hostname in HMAC message content to bind signatures to specific origins
- Always validate that the source IP matches the resolved IP for the signed hostname
- Implement DNS pinning with short TTLs for sensitive operations
- Use HTTPS with certificate validation to provide additional origin verification
- Consider implementing IP allowlisting with dynamic updates based on hostname resolution
Alternative approach using HTTP headers:
from flask import Flask, request
app = Flask(__name__)
@app.before_request
def validate_request_origin():
hostname = request.headers.get('X-Original-Hostname')