Webhook security: How secure are they?
Protect your public webhooks with request signing on Momento.
We recently announced the launch of webhooks – a robust enhancement to Momento Topics that unlocks new workflows like real-time moderation and translations for chat systems. Webhooks offer a powerful means to connect with a broader event-driven architecture (EDA) by enabling you to trigger any POST API endpoint whenever a new message is published. This allows you to initiate various workflows, such as triggering a Step Function workflow or directly invoking a Lambda function. This flexibility enables you to perform immediate processing of a message before forwarding it to another recipient or to initiate an asynchronous workflow for additional post-processing of the sent message.
Are webhooks secure?
While this capability is a powerful tool for developers, one of the first questions many developers ask when building a webhook endpoint is “how do I ensure that messages received on this API are truly being sent by Momento?”
Let’s deep dive on request signing and how it can be used to verify both the sender and integrity of a message received. But before we get into Momento webhooks and how to validate messages, we first need to talk about request signing in general.
Request signing is a security measure used in computer systems to verify the authenticity and integrity of a message or request.Â
Request signing is commonly employed in web applications, APIs, and other distributed systems where communication occurs between different components or services. It provides several security benefits, including:
- Authentication:Â Ensures the sender of the request is who they claim to be.
- Integrity:Â Verifies that the request data has not been altered during transmission.
- Non-repudiation:Â The sender cannot deny sending the request, as the digital signature serves as proof of origin.
Since webhooks are generally public endpoints and not protected by an authentication mechanism, verifying the sender as a trusted source is crucial to the integrity of your system.
Five steps of request signing
Momento implements the following process to digitally sign all requests before they are published to your webhook.
1. Generate a request
When a user initiates a request, the sender (Momento) generates a request message that includes information such as the request method, headers, body, and other relevant details.
2. Create a signature
Momento then creates a digital signature based on the request data. This signature is generated using a signing secret and a HMAC SHA3-256 hash. The signing secret is provided when a webhook is created.
3. Add the signature to the request
The generated signature is appended to the original request, included in the momento-signature header.
4. Publish the signed request
The signed request is sent to the webhook.
5. Verification at the receiver’s end
Upon receiving the request, the recipient (your code) performs the following steps:
- Extracts the request data and the included signature.
- Recalculates the signature using its own copy of the secret key and compares it to the received signature.
- If the calculated signature matches the received signature, the request is considered authentic and has not been tampered with during transit.
![](https://i0.wp.com/www.gomomento.com/wp-content/uploads/2024/06/image-69.png?resize=1053%2C1208&ssl=1)
Now that we have a general idea of what request signing is and the benefits it provides, let’s talk about how it is implemented with Momento webhooks, specifically addressing webhook security.
Each webhook that gets created will get a unique signing secret. Using this signing secret, you can verify whether this request came from Momento. Each HTTP request sent by Momento includes a momento-signature header. This signature is created by combining the signing secret with the request body using a standard HMAC hash.
Obtaining your signing secret:
- When creating a new webhook using the putWebhook API in the Momento SDK, you receive a secret in the response.
const result = await webhookClient.putWebhook(
'exampleCache', 'exampleWebhook', {
destination: new PostUrlWebhookDestination('https://example.com/webhook'),
topicName: 'exampleTopic',
});
if (result instanceof PutWebhook.Success) {
console.log('Webhook created successfully. Secret:', result.secret);
2. You can also get a copy of the signing secret by calling getWebhookSecret API
const result = await webhookClient.getWebhookSecret(
'exampleCache',
'exampleWebhook'
);
if (result instanceof GetWebhookSecret.Success) {
console.log('Webhook secret retrieved successfully:', result.secret);
}
Validating inbound request:
- Retrieve the momento-signature header from the request
- Using HMAC SHA3-256, hash the request body using the signing secret associated with the webhook
- Compare the computed signature to the momento-signature header on the request
import * as crypto from 'crypto';
const didRequestComeFromMomento = (req: Request): boolean => {
const hash = crypto.createHmac("SHA3-256", "the signing secret");
const hashed = hash.update(req.rawBody).digest('hex');
return hashed === req.headers['momento-signature'];
}
Momento also provides utility functions in certain SDKs to assist with the request validation. For example, you could use our JavaScript SDK to do the validation for you:
import {WebhookUtils} from '@gomomento/sdk';
const res = WebhookUtils.validateWebhookRequest({
body: requestBody,
signature,
signingSecret,
});
if (res === WebhookUtils.RequestValidation.VALID) {
// request is valid
} else {
// request is invalid
}
By incorporating signature validation into your webhook destination, you can ensure that the messages received originate exclusively from Momento. This adds a layer of certainty by confirming that the message content aligns with the attached signature. After you validate the request, you can confidently proceed with processing the message. Congratulations, you genuinely verified your messages are from Momento, guarding against potential malicious attempts to spoof your endpoint and enhancing webhook security.