Notifications security
Verify signature and secure agains replay attacks
Introduction
To ensure the security of our webhook payloads, each request is signed with an HMAC signature and includes a timestamp. Clients can verify the signature and check the timestamp to confirm the payload's integrity and authenticity.
Headers
Verifying Signature and Timestamp
X-Signature: The HMAC signature of the payload.
X-Timestamp: The UNIX timestamp when the request was generated. Note that the timestamp also exists inside the payload.
Below are examples of verifying the signatures and checking the timestamps.
import * as crypto from 'crypto';
// Secret key known to both to Krayon and the Client
const secretKey = 'supersecretkey';
function verifySignatureAndTimestamp(receivedPayload: string, receivedSignature: string, receivedTimestamp: string, maxAgeSeconds: number = 300): [boolean, string] {
// Calculate the expected signature
const hmac = crypto.createHmac('sha256', secretKey);
hmac.update(receivedPayload);
const expectedSignature = hmac.digest('hex');
// Verify the signature
if (receivedSignature !== expectedSignature) {
return [false, "Invalid signature"];
}
// Verify the timestamp
const currentTimestamp = Math.floor(Date.now() / 1000);
const receivedTimestampNumber = parseInt(receivedTimestamp, 10);
if (Math.abs(currentTimestamp - receivedTimestampNumber) > maxAgeSeconds) {
return [false, "Timestamp is not within the acceptable range"];
}
return [true, "Valid signature and timestamp"];
}
// Example usage
const receivedPayload = '{"data": "example_payload", "timestamp": "1633024800", "nonce": "unique-nonce"}';
const receivedSignature = 'received_signature_from_headers';
const receivedTimestamp = '1633024800';
const [isValid, message] = verifySignatureAndTimestamp(receivedPayload, receivedSignature, receivedTimestamp);
console.log(message);
import hmac
import hashlib
import json
import time
# Secret key known to both to Krayon and the Client
secret_key = b'supersecretkey'
def verify_signature_and_timestamp(received_payload, received_signature, received_timestamp, max_age_seconds=300):
# Calculate the expected signature
expected_signature = hmac.new(secret_key, received_payload.encode(), hashlib.sha256).hexdigest()
# Verify the signature
if not hmac.compare_digest(received_signature, expected_signature):
return False, "Invalid signature"
# Verify the timestamp
current_timestamp = int(time.time())
received_timestamp = int(received_timestamp)
if abs(current_timestamp - received_timestamp) > max_age_seconds:
return False, "Timestamp is not within the acceptable range"
return True, "Valid signature and timestamp"
# Example usage
received_payload = '{"data": "example_payload", "timestamp": "1633024800", "nonce": "unique-nonce"}'
received_signature = 'received_signature_from_headers'
received_timestamp = '1633024800'
is_valid, message = verify_signature_and_timestamp(received_payload, received_signature, received_timestamp)
print(is_valid, message)
Summary
By following these examples, clients can ensure that the payloads received from the webhook are authentic and have not been tampered with. Both the signature and the timestamp are verified to protect against replay attacks and ensure data integrity.
Updated 6 months ago