JAVASCRIPT
Verify Webhook Signatures for Security
Enhance webhook security by implementing signature verification in Node.js. Validate incoming requests to ensure they originate from trusted sources, preventing spoofing and tampering.
const express = require('express');
const bodyParser = require('body-parser');
const crypto = require('crypto');
const app = express();
// Your secret key for verifying webhooks
const WEBHOOK_SECRET = 'your_super_secret_webhook_key'; // CHANGE THIS IN PRODUCTION!
// A raw body parser is needed to calculate the signature correctly
app.use(bodyParser.json({ verify: (req, res, buf) => {
req.rawBody = buf.toString();
}}));
app.post('/webhook', (req, res) => {
const signature = req.headers['x-webhook-signature']; // Or your specific header name
if (!signature) {
return res.status(401).send('No signature header provided.');
}
// Recompute the signature using the raw body and your secret
// Example: HMAC SHA256
const hmac = crypto.createHmac('sha256', WEBHOOK_SECRET);
hmac.update(req.rawBody);
const expectedSignature = `sha256=${hmac.digest('hex')}`; // Adjust prefix if needed
// Compare the expected signature with the one from the header
// Use crypto.timingSafeEqual to prevent timing attacks
const isSignatureValid = crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
if (!isSignatureValid) {
return res.status(403).send('Invalid signature.');
}
// Signature is valid, process the webhook payload
console.log('Webhook received:', req.body);
res.status(200).send('Webhook received and processed.');
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Webhook listener running on port ${PORT}`);
});
How it works: This Node.js Express snippet demonstrates how to securely verify the signature of incoming webhook requests. Many services send a cryptographic signature in a header (e.g., `X-Webhook-Signature`) that is computed using the request's raw body and a shared secret key. This code re-computes the signature on the server-side using the `crypto` module and compares it to the received signature. Using `crypto.timingSafeEqual` is crucial to prevent timing attacks. This verification process ensures that the webhook request is legitimate and has not been tampered with, adding a vital layer of security to your API integrations.