How to Secure Webhook Deliveries

To ensure that webhook payloads are securely transmitted and verified. This guide explains how to configure and validate webhook deliveries using a shared secret.

How It Works

When setting up a webhook, a secret is configured on both the sender (our system) and the receiver (your endpoint). Each webhook payload is signed using this secret, allowing the receiver to verify its authenticity.

Step 1: Configuring Your Webhook Secret

  1. When creating a webhook in our system, specify a unique secret key. This secret should be a strong, randomly generated string.
  2. Store this secret securely on your server; it should never be exposed publicly.

Step 2: Receiving Webhook Payloads

When your server receives a webhook event, the request will include an X-Signature header containing a HMAC signature of the payload. Example header:
X-Signature: sha256=abcdef1234567890...

Step 3: Validating the Webhook Signature

To verify the webhook payload:
  1. Retrieve the X-Signature value from the request headers.
  2. Compute the HMAC SHA-256 signature of the request payload using your webhook secret.
  3. Compare the computed signature with the one in the X-Signature header.
  4. If they match, the webhook is valid.

(Python)

import hashlib
import hmac
import json

def verify_webhook_signature(secret, payload, signature):
  computed_signature = hmac.new(secret.encode(), payload.encode(), hashlib.sha256).hexdigest()
  expected_signature = f"sha256={computed_signature}"
  return hmac.compare_digest(expected_signature, signature)

# Example usage:
secret = "your_webhook_secret"
payload = json.dumps({"event": "example"})
received_signature = "sha256=abcdef1234567890..."

if verify_webhook_signature(secret, payload, received_signature):
  print("Valid webhook received!")
else:
  print("Invalid webhook signature!")

(JavaScript)

const crypto = require('crypto');

function verifyWebhookSignature (secret, payload, signature) {
const computedSignature = `sha256=${crypto.createHmac('sha256', secret)
.update(payload)
.digest('hex')}`;
return crypto.timingSafeEqual(Buffer.from(computedSignature), Buffer.from(signature));
}

// Example usage:
const secret = "your_webhook_secret";
const payload = JSON.stringify({ event: "example" });
const receivedSignature = "sha256=abcdef1234567890...";

if (verifyWebhookSignature(secret, payload, receivedSignature)) {
console.log("Valid webhook received!");
} else {
console.log("Invalid webhook signature!");
}

Security Considerations

  • Always use HTTPS to prevent interception of webhook payloads.
  • Reject webhook requests that fail signature validation.
  • Rotate secrets periodically to enhance security.
By following this guide, you ensure that webhook deliveries are secure and trusted.