Skip to content

Webhook Signing

Key idea:

Webhook signing is a mechanism where the sender adds an HMAC signature of the payload to an HTTP header, and the receiver verifies the signature with a shared secret. Without signing, anyone who knows the webhook URL can send fake events. Standard pattern: HMAC-SHA256(secret, timestamp + body) → header X-Hub-Signature-256. Used by Stripe, GitHub, Telegram, YooKassa, Slack.

Below: details, example, related terms, FAQ.

Check your site's security →

Details

  • HMAC algorithm: SHA-256 (standard). SHA-1 deprecated
  • Payload: usually includes timestamp for replay protection
  • Header name: not standardized — X-Signature, X-Hub-Signature-256, Stripe-Signature
  • Timing-safe comparison: hash_equals() in PHP, crypto.timingSafeEqual() in Node
  • Secret rotation: provider gives a grace period — 2 secrets valid concurrently

Example

// PHP verification
$expected = hash_hmac("sha256", $body, $secret);
$actual = $_SERVER["HTTP_X_SIGNATURE_256"];
if (!hash_equals($expected, $actual)) return 401;

Related Terms

How to Implement HMAC Signature for Webhooks

Implementing HMAC signature for webhooks involves several steps to ensure secure communication between your server and the service sending the webhook. Here’s a practical guide:

  1. Generate a Shared Secret: This is a key that both the sender and receiver must keep confidential. It can be a random string generated using a secure random function.
  2. Construct the Payload: The payload is the data you want to send in the webhook. For example, if you are sending a user creation event, the payload might look like this:
{ "user_id": "12345", "event": "user.created" }
  1. Create the HMAC Signature: Use the HMAC-SHA256 algorithm with the shared secret and the payload. The signature also often includes a timestamp to prevent replay attacks. In Python, it would look like this:
import hmac
import hashlib
import json

shared_secret = b'secret_key'
payload = json.dumps({"user_id": "12345", "event": "user.created"})
timestamp = str(int(time.time())).encode()

message = timestamp + payload.encode()
signature = hmac.new(shared_secret, message, hashlib.sha256).hexdigest()
  1. Send the Webhook: Include the signature and timestamp in the HTTP headers when sending the webhook:
headers = {"X-Hub-Signature-256": signature, "X-Timestamp": timestamp}
requests.post(url, headers=headers, json=payload)
  1. Verify the Signature: On the receiving end, you must verify the signature by reconstructing it using the shared secret and comparing it to the received signature.
received_signature = headers.get("X-Hub-Signature-256")
# Recreate the signature and compare

By following these steps, you can securely implement HMAC signature verification for your webhooks.

Common Errors in HMAC Signature Verification

When implementing HMAC signature verification for webhooks, developers often encounter common errors that can lead to security vulnerabilities. Understanding these errors can help in troubleshooting and ensuring secure communications.

  • Signature Mismatch: This is the most common error. It occurs when the calculated signature on the receiver's side does not match the one sent by the sender. Common causes include:
    • Incorrect shared secret used during signature creation or verification.
    • Changes to the payload during transmission (e.g., URL encoding issues).
    • Omission of the timestamp or incorrect timestamp format.
  • Replay Attacks: If a webhook does not include a timestamp, it can be susceptible to replay attacks. Attackers can resend a valid webhook to trigger actions. Always include a timestamp and verify that it is within an acceptable time window (e.g., 5 minutes).
  • Improper Handling of Headers: Ensure that the headers are correctly parsed and not altered during transmission. For instance, case sensitivity in header names can lead to mismatches.
  • Encoding Issues: Ensure that the payload is consistently encoded when generating and verifying the signature. For instance, differences in character encoding (UTF-8 vs. ASCII) can lead to different hashes.

By being aware of these common errors, developers can implement more robust HMAC signature verification and enhance the security of their webhook integrations.

Best Practices for Webhook Signing with HMAC

Securing webhooks using HMAC signatures is crucial for preventing unauthorized access and ensuring data integrity. Below are some best practices for implementing HMAC signature verification:

  • Use Strong Shared Secrets: Generate a long, random shared secret to make it difficult for attackers to guess. Avoid using easily predictable strings or secrets.
  • Include Timestamps: Always include a timestamp in the webhook payload to mitigate replay attacks. Implement a time window for accepting timestamps to ensure they are recent.
  • Limit IP Addresses: If possible, restrict incoming webhook requests to known IP addresses of the sender. This adds an additional layer of security.
  • Log All Webhook Events: Maintain detailed logs of all webhook events, including the received payload, headers, and verification results. This will help in auditing and troubleshooting issues.
  • Verify Payload Integrity: In addition to verifying the HMAC signature, consider implementing additional checks for the payload structure and contents to ensure it meets your application’s requirements.
  • Rotate Shared Secrets Regularly: Periodically change the shared secret used for HMAC signing and update both sender and receiver accordingly. This practice minimizes the risk of compromise.
  • Use HTTPS: Always use HTTPS for transmitting webhooks to encrypt the data in transit and protect it from eavesdropping and man-in-the-middle attacks.

By adhering to these best practices, developers can significantly enhance the security of their webhook implementations using HMAC signatures.

HeadersCSP, HSTS, X-Frame-Options, etc.
SSL/TLSEncryption and certificate
ConfigurationServer settings and leaks
Grade A-FOverall security score

Why teams trust us

OWASP
guidelines
15+
security headers
<2s
result
A–F
security grade

How it works

1

Enter site URL

2

Security headers analyzed

3

Get grade A–F

What Does the Security Analysis Check?

The tool checks HTTP security headers, SSL/TLS configuration, server info leaks, and protection against common attacks (XSS, clickjacking, MIME sniffing). A grade fromA to F shows overall security level.

Header Analysis

Checking Content-Security-Policy, HSTS, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, and more.

SSL Check

TLS version, certificate expiry, chain of trust, HSTS support.

Leak Detection

Finding exposed server versions, debug modes, open configs, and directories.

Report with Recommendations

Detailed report explaining each issue with specific steps to fix it.

Who uses this

Security teams

HTTP header audit

DevOps

config verification

Developers

CSP & HSTS setup

Auditors

compliance checks

Common Mistakes

Missing Content-Security-PolicyCSP is the primary XSS defense. Without it, script injection is much easier.
Missing HSTS headerWithout HSTS, HTTPS-to-HTTP downgrade attacks are possible. Enable Strict-Transport-Security.
Server header exposes versionServer: Apache/2.4.52 helps attackers find exploits. Hide the version.
X-Frame-Options not setSite can be embedded in iframe for clickjacking. Set DENY or SAMEORIGIN.
Missing X-Content-Type-OptionsWithout nosniff, browsers may misinterpret file types (MIME sniffing).

Best Practices

Start with basic headersMinimum: HSTS, X-Frame-Options, X-Content-Type-Options, Referrer-Policy. Takes 5 minutes.
Implement CSP graduallyStart with Content-Security-Policy-Report-Only, monitor violations, then enforce.
Hide server headersRemove Server, X-Powered-By, X-AspNet-Version from responses.
Configure Permissions-PolicyRestrict camera, microphone, geolocation access — only what is actually used.
Check after every deploySecurity headers can be overwritten during server configuration updates.

Get more with a free account

Security check history and HTTP security header monitoring.

Sign up free

Learn more

Frequently Asked Questions

Why HMAC instead of just a shared secret in a header?

A secret in a header travels in plain. HMAC signs the body; the secret is never transmitted.

Replay attack protection?

Timestamp + nonce in payload. Receiver confirms fresh timestamp (5 min window) and unused nonce.

Which providers use it?

Stripe (Stripe-Signature), GitHub (X-Hub-Signature-256), Slack (X-Slack-Signature), Telegram (X-Telegram-Bot-Api-Secret-Token), YooKassa.

Try the live tool that powered this guide

Free plan — 10 monitors, checks every 5 min, no card required. Upgrade for 1-minute interval and multi-region monitoring.