Verifying notifications
Because webhook endpoints are accessible to the public, they're prone to malicious attacks. That's why it's a best practice to verify webhook notifications to determine if they're from Squarespace.
Structure of a Squarespace notification
Read the Webhook overview to see how a Squarepsace notification is structured.
1. Retrieve the webhook subscription's secret from its secure location
Every Squarespace notification includes a Squarespace-Signature
header.
To verify this header, you must have access to the secret
from the appropriate Webhook Subscription
.
A secret
is only returned when creating a subscription or rotating a secret, and is always a hexadecimal value.
2. Generate the expected Squarespace-Signature
Squarespace generates the Squarespace-Signature
header using HMAC with SHA-256.
Compute the expected signature by signing the payload with the secret
from the Webhook Subscription
as the key:
Expected signature = HMAC-SHA256(hexToBytes(secret
), request payload)
Note: The hex-encoded secret should be decoded to raw bytes when constructing the HMAC otherwise the expected signature won't match. The request payload is the raw HTTP request body as a UTF-8 string without any formatting applied.
3. Compare the signatures
Compare the expected signature with the Squarespace-Signature
header in the notification.
If the signatures match, then the notification was sent from Squarespace.
Note: Use a constant-time comparison function when checking if two signatures match to protect against timing attacks.
Examples
Node
const crypto = require('crypto');
const expectedSignature = crypto.createHmac('sha256', Buffer.from(secret, 'hex'))
.update(payload)
.digest('hex');
const isFromSquarespace = crypto.timingSafeEqual(Buffer.from(expectedSignature), Buffer.from(headerSignature))
OpenSSL
echo -n $PAYLOAD | openssl sha256 -mac hmac -macopt hexkey:$SECRET