JAVASCRIPT
Enhancing Webhook Security: Verifying Signatures in Node.js
Learn to implement webhook signature verification in Node.js to ensure incoming webhook payloads are authentic and untampered, improving API security.
const express = require('express');
const crypto = require('crypto');
const bodyParser = require('body-parser'); // For raw body access
const app = express();
const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET || 'your_super_secret_key_here'; // Use environment variable!
// IMPORTANT: body-parser must be configured to parse raw body
// This allows us to access req.rawBody which is crucial for signature verification.
app.use(bodyParser.json({
verify: (req, res, buf) => {
req.rawBody = buf; // Store the raw body buffer
},
}));
// Example webhook endpoint
app.post('/webhook', (req, res) => {
const signature = req.headers['x-hub-signature-256'] || req.headers['x-webhook-signature']; // Check your provider's header name
if (!signature) {
console.warn('Webhook received without signature.');
return res.status(401).send('Unauthorized: No signature provided.');
}
// Recreate the expected signature
// The hash algorithm (sha256) and encoding (hex) depend on the provider.
const hmac = crypto.createHmac('sha256', WEBHOOK_SECRET);
hmac.update(req.rawBody);
const expectedSignature = `sha256=${hmac.digest('hex')}`; // Match format, e.g., 'sha256=' prefix
// Compare signatures
// Using crypto.timingSafeEqual to prevent timing attacks
const isSignatureValid = crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expectedSignature));
if (!isSignatureValid) {
console.warn('Webhook received with invalid signature.');
return res.status(403).send('Forbidden: Invalid signature.');
}
// Signature is valid, process the webhook payload
console.log('Webhook payload verified:', req.body);
res.status(200).send('Webhook received and verified.');
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server listening on port ${PORT}`);
console.log('Webhook Secret:', WEBHOOK_SECRET); // For development, do NOT log in production
});
How it works: This Node.js snippet demonstrates how to securely verify the signature of incoming webhook payloads. Many API providers send a signature (often a hash of the payload) in a request header to allow recipients to confirm the authenticity and integrity of the data. This code uses Node.js's `crypto` module to generate an HMAC hash of the raw request body using a shared secret and then compares it with the signature provided in the header. Utilizing `bodyParser` with a `verify` function is crucial to access the raw request body, and `crypto.timingSafeEqual` is used for a secure comparison to prevent timing attacks.