DEV Community

丁久
丁久

Posted on • Originally published at dingjiu1989-hue.github.io

Webhook Security Best Practices

This article was originally published on AI Study Room. For the full version with working code examples and related articles, visit the original post.

Webhook Security Best Practices

Webhook Security Best Practices

Webhook Security Best Practices

Webhook Security Best Practices

Webhook Security Best Practices

Webhook Security Best Practices

Webhook Security Best Practices

Webhook Security Best Practices

Webhook Security Best Practices

Webhook Security Best Practices

Why Webhook Security Matters

Webhooks are HTTP callbacks that allow services to push real-time events to your application. Unlike APIs where you initiate the request, webhooks are delivered to a public endpoint that anyone with the URL can call. Without proper security, an attacker can replay webhook events, send fake event data, or probe your internal infrastructure.

Threat Model

| Threat | Impact | Likelihood | |--------|--------|------------| | Fake webhook events | Application processes false data | High | | Replay attacks | Duplicate processing of legitimate events | Medium | | Payload tampering | Corrupted data processed as valid | Medium | | Reconnaissance | Attacker probes internal network | Low | | DDoS via webhooks | Service overload from fake events | Medium |

Defense 1: Signature Verification

Every webhook provider signs their payloads. Your endpoint must verify this signature before processing.

Stripe-Style Signatures

import hmac

import hashlib

def verify_stripe_signature(payload, sig_header, secret):

"""Verify Stripe webhook signature."""

Signature format: t=timestamp,v1=signature

parts = dict(item.split('=', 1) for item in sig_header.split(','))

if 'v1' not in parts or 't' not in parts:

return False

timestamp = parts['t']

expected_sig = parts['v1']

Prevent replay: signature must be within 5 minutes

if abs(int(timestamp) - time.time()) > 300:

return False

Compute expected signature

signed_payload = f"{timestamp}.{payload}".encode()

computed_sig = hmac.new(

secret.encode(),

signed_payload,

hashlib.sha256

).hexdigest()

Constant-time comparison

return hmac.compare_digest(computed_sig, expected_sig)

GitHub-Style Signatures

const crypto = require('crypto');

function verifyGitHubSignature(req, secret) {

const signature = req.headers['x-hub-signature-256'];

if (!signature) return false;

const payload = JSON.stringify(req.body);


Read the full article on AI Study Room for complete code examples, comparison tables, and related resources.

Found this useful? Check out more developer guides and tool comparisons on AI Study Room.

Top comments (0)