Portal Community

Security Controls Summary

ControlProtects AgainstConfiguration
HMAC-SHA256 signatureForged requests from unauthorized sendersAlways required (cannot disable)
Secret rotationCompromised secretsManual via API; 24h grace period
IP allowlistRequests from unexpected IP rangesOptional; CIDR notation
Payload size limitDenial-of-service via large payloadsDefault 512 KB; max 10 MB
Timestamp validationReplay attacks (old requests re-submitted)Configurable tolerance (default ±5 min)
Rate limitingFlooding from legitimate but misbehaving sendersPer-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.