Flow Studio
Webhook Security
Defense-in-depth security controls for webhook endpoints — secret rotation, IP allowlists, payload size limits, and replay attack prevention.
Security Controls Summary
| Control | Protects Against | Configuration |
|---|---|---|
| HMAC-SHA256 signature | Forged requests from unauthorized senders | Always required (cannot disable) |
| Secret rotation | Compromised secrets | Manual via API; 24h grace period |
| IP allowlist | Requests from unexpected IP ranges | Optional; CIDR notation |
| Payload size limit | Denial-of-service via large payloads | Default 512 KB; max 10 MB |
| Timestamp validation | Replay attacks (old requests re-submitted) | Configurable tolerance (default ±5 min) |
| Rate limiting | Flooding from legitimate but misbehaving senders | Per-webhook rate limit (requests/minute) |
Timestamp Replay Prevention
Include a Unix timestamp in the signature payload to prevent replays. The sender should sign {timestamp}.{body} and include the timestamp in the X-Webhook-Timestamp header:
# Sender adds timestamp to signature
import time, hmac, hashlib
timestamp = int(time.time())
body = json.dumps(payload)
signed_payload = f"{timestamp}.{body}"
signature = hmac.new(secret.encode(), signed_payload.encode(), hashlib.sha256).hexdigest()
headers = {
"X-Webhook-Timestamp": str(timestamp),
"X-Webhook-Signature": f"sha256={signature}"
}
The verifier rejects requests where |now - timestamp| > 300 seconds (configurable).
IP Allowlist Configuration
{
"webhookId": "wh-abc123",
"ipAllowlist": [
"192.168.1.0/24",
"10.0.0.5/32",
"2001:db8::/32"
]
}
Requests from IPs not in the allowlist receive 403 Forbidden. The IP check happens before signature verification to avoid unnecessary cryptographic operations.
Known sender IPs: Many SaaS platforms (Shopify, GitHub, Stripe) publish their webhook IP ranges. Use these ranges in your IP allowlist to add an extra authentication layer on top of signature verification.