保护您的 Node.js 后端:Didit Webhook 的 HMAC 验证 (ZH)
为 webhook 实施强大的安全措施对于数据完整性和防止未经授权的访问至关重要。本指南重点介绍如何在 Node.js 中对 Didit webhook 进行 HMAC 签名验证。.

保护数据完整性HMAC 签名验证对于验证 Webhook 有效负载的真实性和完整性至关重要,可保护您的后端免受篡改或欺诈请求的影响。
防止重放攻击时间戳验证与 HMAC 签名相结合,为防御重放攻击增加了关键的防御层,确保只处理最新的通知。
无缝集成Didit 的开发者优先方法提供了清晰的文档和工具,使安全 Webhook 处理集成到您的 Node.js 应用程序中变得简单高效。
Didit 的安全基础设施Didit 平台在设计时考虑了安全性,通过具有强大 HMAC 签名验证的 Webhook 提供实时 KYC 通知,使您能够构建可信赖、合规的身份解决方案。
Webhook 安全的关键需求
Webhook 是服务之间实时通信的强大工具,可实现即时更新和事件驱动架构。在身份验证的背景下,Didit 使用 Webhook 通知您的后端验证会话完成、AML 筛选结果或其他关键的身份相关事件。虽然效率极高,但 Webhook 也带来了安全挑战。如果没有适当的验证,恶意行为者可能会发送伪造或篡改的 Webhook 有效负载,从而导致不正确的数据处理、未经授权的操作,甚至系统遭到破坏。
这就是 HMAC(基于哈希的消息认证码)签名验证不可或缺的原因。HMAC 提供了一种密码学机制来验证消息的真实性和完整性。通过使用共享密钥,您的后端可以确保 Webhook 有效负载源自 Didit,并且在传输过程中未被篡改。对于任何处理敏感身份数据的系统,例如 Didit 的身份验证、AML 筛选或地址证明服务处理的数据,这种级别的安全性不仅仅是最佳实践,它是一种必要性。
理解 HMAC 签名验证
HMAC 验证通过使用只有 Didit 和您的应用程序知道的密钥为每个 Webhook 有效负载生成唯一的签名。当您的 Node.js 后端收到 Webhook 时,它使用其密钥副本执行相同的签名计算。如果计算出的签名与 Webhook 标头中提供的签名匹配,您可以确信有效负载是真实的且未被篡改。
Didit 的 Webhook 包含一个包含 HMAC-SHA256 签名的 X-Signature 标头和一个 X-Timestamp 标头。时间戳对于防止重放攻击至关重要。当攻击者拦截合法的 Webhook 并稍后重新发送时,就会发生重放攻击。通过验证时间戳是新鲜的(例如,在 5 分钟窗口内),您可以丢弃旧的、可能被重放的请求。
在 Node.js 中实现 HMAC 验证
让我们逐步了解在 Node.js Express 应用程序中为 Didit Webhook 实现 HMAC 签名验证的步骤。您需要访问您的 Webhook 密钥,该密钥可以在您的 Didit 业务控制台或通过管理 API 获取。
1. 配置您的 Webhook 端点
首先,设置一个可以接收 POST 请求的 Express 端点。在任何 JSON 解析中间件之前访问原始请求正文至关重要,因为签名是根据原始有效负载计算的。
const express = require('express');
const crypto = require('crypto');
const bodyParser = require('body-parser');
const app = express();
const DIDIT_WEBHOOK_SECRET = process.env.DIDIT_WEBHOOK_SECRET; // 安全存储!
// 获取原始正文的中间件
app.use(bodyParser.json({ verify: (req, res, buf) => {
req.rawBody = buf.toString();
}}));
app.post('/api/webhooks/didit', (req, res) => {
// Webhook 处理逻辑将在此处
res.status(200).send('Webhook received');
});
app.listen(3000, () => console.log('Server running on port 3000'));
2. 验证 HMAC 签名
在您的 Webhook 处理程序中,您将从标头中提取时间戳和签名,重构已签名的有效负载,并将您计算的签名与 Didit 提供的签名进行比较。
app.post('/api/webhooks/didit', (req, res) => {
const signatureHeader = req.headers['x-signature'];
const timestampHeader = req.headers['x-timestamp'];
const rawBody = req.rawBody;
if (!signatureHeader || !timestampHeader || !rawBody) {
return res.status(400).send('Missing webhook headers or body.');
}
const [algorithm, diditSignature] = signatureHeader.split('=');
if (algorithm !== 'sha256') {
return res.status(400).send('Unsupported signature algorithm.');
}
// 重构已签名的有效负载字符串
const signedPayload = `${timestampHeader}.${rawBody}`;
// 计算您自己的签名
const expectedSignature = crypto
.createHmac('sha256', DIDIT_WEBHOOK_SECRET)
.update(signedPayload)
.digest('hex');
// 安全地比较签名
const signatureMatches = crypto.timingSafeEqual(
Buffer.from(diditSignature, 'utf8'),
Buffer.from(expectedSignature, 'utf8')
);
if (!signatureMatches) {
console.warn('Webhook signature mismatch!');
return res.status(401).send('Invalid signature.');
}
// 签名有效,现在检查时间戳
// ... (时间戳验证在下一步)
// 处理事件
console.log('Webhook validated successfully:', req.body);
res.status(200).send('Webhook received and processed.');
});
3. 验证时间戳
验证签名后,确保 Webhook 不是重放。一种常见的做法是允许一个小的容忍窗口(例如,5 分钟)以应对网络延迟。
// ... (在 webhook 处理程序中,签名验证之后)
const fiveMinutesAgo = Date.now() / 1000 - (5 * 60); // 5 分钟(秒)
const eventTimestamp = parseInt(timestampHeader, 10);
if (isNaN(eventTimestamp) || eventTimestamp < fiveMinutesAgo) {
console.warn('Webhook timestamp too old or invalid!');
return res.status(401).send('Invalid or old timestamp.');
}
// 现在您可以安全地解析和处理 JSON 正文
try {
const event = JSON.parse(rawBody);
console.log('Processed Didit event:', event);
// 示例:根据 event.database_validation.status 更新用户状态
// Didit 的数据库验证报告结构:
// const validationStatus = event.database_validation.status;
// const matchType = event.database_validation.match_type;
// console.log(`Validation Status: ${validationStatus}, Match Type: ${matchType}`);
res.status(200).send('Webhook received and processed.');
} catch (error) {
console.error('Error parsing webhook body:', error);
res.status(400).send('Invalid JSON body.');
}
});
Webhook 处理的最佳实践
- 安全存储密钥:切勿将您的 Webhook 密钥硬编码。使用环境变量或安全的密钥管理服务。
- 幂等性:将您的 Webhook 处理程序设计为幂等。这意味着多次处理同一 Webhook(例如由于重试)应与处理一次具有相同的效果。
- 异步处理:对于长时间运行的任务,立即使用 200 OK 响应确认 Webhook,然后使用消息队列异步处理有效负载。这可以防止超时并确保 Didit 不会不断重试 Webhook。
- 日志和监控:为所有收到的 Webhook 实施强大的日志记录,包括验证失败。监控您的 Webhook 端点是否存在异常活动或高错误率。
- 错误处理:返回适当的 HTTP 状态码(例如,400 表示错误请求,401 表示未授权,500 表示服务器错误),以帮助 Didit 了解是否需要重试。
Didit 如何提供帮助
Didit 旨在成为一个 AI 原生、开发者优先的身份平台,使 Webhook 处理等安全集成变得简单可靠。我们的模块化架构意味着您可以轻松插入身份检查,包括身份验证、被动和主动活体检测以及 AML 筛选和监控,并通过安全 Webhook 接收实时更新。Didit 提供清晰的文档和 Webhook 集成示例,确保您可以快速建立强大、安全的通信渠道。
我们相信让身份验证变得易于访问和强大。这就是我们提供免费核心 KYC、按成功检查付费模式以及绝对零设置费用的原因。通过利用 Didit 平台,您可以获得一个全球性、可扩展的解决方案,该解决方案可自动化信任并协调风险,同时保持最高的安全标准,包括用于实时通知的 HMAC 签名验证。
准备好开始了吗?
准备好了解 Didit 的实际应用了吗?立即获取免费演示。
使用Didit 的免费套餐免费开始验证身份。