Webhook Signature Verification
Webhook Signature Verification Guide#
Overview#
All webhook requests from Kobble are cryptographically signed to ensure authenticity and integrity. You must validate the signature of every webhook request before processing it. This prevents unauthorized access and ensures the message hasn't been tampered with.
Why Validate Signatures?#
Signature validation provides:Authentication: Confirms the request came from Kobble
Integrity: Ensures the payload hasn't been modified in transit
Security: Protects against spoofed or malicious requests
Never process webhook requests without validating their signatures.
Webhook Request Structure#
When Kobble sends a webhook, you receive a JSON payload with the following structure:x-amz-sns-message-id: Unique message identifier
x-amz-sns-message-type: One of Notification, SubscriptionConfirmation, or UnsubscribeConfirmation
Request Body (JSON)#
{
"Type": "Notification",
"MessageId": "95df01b4-ee98-5cb9-9903-4c221d41eb5e",
"TopicArn": "arn:aws:sns:us-east-1:123456789012:ExampleTopic",
"Message": "{\"id\":\"d2e89f3f-48bd-4bfc-8fd0-2d6b8e7207c1\",\"type\":\"transaction-create\",\"entity_id\":\"...\",\"client_id\":\"...\",\"created_at\":\"2024-09-18T11:47:03.123Z\"}",
"Timestamp": "2015-01-02T12:00:00.000Z",
"SignatureVersion": "1",
"Signature": "EXAMPLE1234567890...",
"SigningCertURL": "https://sns.us-east-1.amazonaws.com/SimpleNotificationService-123456789.pem",
"Subject": null,
"UnsubscribeURL": "https://sns.us-east-1.amazonaws.com/?Action=Unsubscribe&..."
}
Key Fields for Validation#
| Field | Description |
|---|
Type | Message type: Notification, SubscriptionConfirmation, or UnsubscribeConfirmation |
MessageId | Unique identifier for this message |
Message | The actual webhook event data (JSON string) |
Timestamp | ISO 8601 timestamp when the message was created |
SignatureVersion | Signature algorithm version: "1" (RSA-SHA1) or "2" (RSA-SHA256) |
Signature | Base64-encoded RSA signature |
SigningCertURL | HTTPS URL to download the public certificate |
Signature Validation Process#
The validation process consists of four main steps:Step 1: Validate Certificate URL#
Before downloading the certificate, verify the SigningCertURL is legitimate:Must end with .pem extension
Hostname must match pattern: sns.[region].amazonaws.com (or .amazonaws.com.cn)
Security Note: Never download certificates from untrusted URLs. This validation prevents certificate injection attacks.Step 2: Download the Certificate#
Download the public certificate from the validated URL:Best Practice: Cache certificates with a reasonable TTL (e.g., 24 hours) to reduce download overhead. Certificates are rotated infrequently.Step 3: Build the String to Sign#
Create the canonical string that was signed by constructing it from the message fields:1.
Sort all field names alphabetically
2.
For each field, include it only if:It's in the list of signable fields
It's not null or undefined
3.
Format each field as: FieldName\nFieldValue\n
Message
{"id":"123","type":"transaction-create"}
MessageId
95df01b4-ee98-5cb9-9903-4c221d41eb5e
Timestamp
2015-01-02T12:00:00.000Z
TopicArn
arn:aws:sns:us-east-1:123456789012:ExampleTopic
Type
Notification
Field names are case-sensitive
Fields must be sorted alphabetically
Include the newline (\n) after both field name and value
Skip null and undefined values
Step 4: Verify the Signature#
Use the downloaded certificate to verify the signature:
Complete Implementation Examples#
Node.js/TypeScript#
Python#
Express.js Middleware Example#
Security Best Practices#
1. Certificate Caching#
Cache certificates with a reasonable TTL (24 hours) to reduce download overhead:2. Timeout Protection#
Always set timeouts when downloading certificates:3. Rate Limiting#
Implement rate limiting on your webhook endpoint to prevent abuse:4. Comprehensive Logging#
Log validation failures for security monitoring:5. Fail Securely#
Always reject requests if validation fails:BAD: Processing without validation
Common Pitfalls and Solutions#
1. Case Sensitivity#
Problem: Field names are case-sensitive. Message ≠ message.Solution: Always use exact field names as received.2. Field Ordering#
Problem: Fields must be sorted alphabetically when building the string to sign.Solution: Always sort keys before building the string:3. Null Handling#
Problem: Null or undefined fields should be skipped.Solution: Check for null/undefined before including:4. Certificate URL Validation#
Problem: Downloading certificates from untrusted URLs.Solution: Always validate the URL pattern before downloading:5. Signature Version Support#
Problem: Only supporting one signature version.Solution: Support both versions:
Testing Signature Validation#
Test with Valid Message#
Test Invalid Signature#
Test Invalid Certificate URL#
Troubleshooting#
Issue: Signature validation always fails#
1.
Incorrect string-to-sign construction
2.
Wrong signature algorithm
3.
Certificate download failure
1.
Log the string-to-sign to verify it matches expected format
2.
Verify signature version matches algorithm used
3.
Check certificate download succeeds
4.
Verify signature is properly base64-decoded
Issue: Certificate download times out#
Implement certificate caching
Increase timeout (but not too much)
Add retry logic with exponential backoff
Issue: Validation works in test but fails in production#
1.
Different message structure in production
2.
Certificate caching issues
3.
Network/firewall blocking certificate downloads
Compare test vs production message structure
Check network connectivity to certificate URLs
Additional Resources#
Summary#
Signature validation is critical for webhook security. Always:1.
Validate certificate URLs before downloading
2.
Build the string-to-sign correctly (alphabetical order, correct fields)
3.
Verify signatures using the correct algorithm (RSA-SHA1 or RSA-SHA256)
4.
Cache certificates to improve performance
5.
Log validation failures for security monitoring
6.
Reject requests with invalid signatures
By following this guide, you'll ensure your webhook integration is secure and reliable.Modified at 2025-11-20 04:51:25