Webhook 详解:签名载荷与重试逻辑

Backend2026-10-28TryQuickToolBox

你已经构建了一个 API,现在需要在事件发生时通知其他服务。轮询效率低下,所以你转向了 Webhook。但很快你会发现 Webhook 可能会失败、被伪造或导致重复处理。本文介绍如何通过签名载荷保护 Webhook,并实现健壮的重试逻辑。

什么是 Webhook?

Webhook 是用户定义的 HTTP 回调。当你的系统中发生事件(例如支付成功)时,你向订阅者提供的 URL 发送 HTTP POST 请求。载荷通常包含 JSON 或表单格式的事件数据。

Webhook 使服务之间能够实时通信,而无需持续轮询。它们被支付网关、CI/CD 工具和 SaaS 平台广泛使用。

为什么需要保护 Webhook?

如果没有安全措施,任何知道 Webhook URL 的人都可以发送虚假请求,导致数据损坏或欺诈。此外,攻击者可能重放旧请求。使用共享密钥对载荷进行签名可确保真实性和完整性。

使用 HMAC 对载荷进行签名

HMAC(基于哈希的消息认证码)是对 Webhook 进行签名的常用方法。发送方和接收方共享一个密钥。发送方使用密钥计算载荷的 HMAC,并将其包含在头部(例如 X-Signature)中。接收方重新计算 HMAC 并进行比较。

分步指南:发送签名 Webhook

  1. 创建载荷(JSON)。
  2. 使用密钥计算载荷的 HMAC-SHA256。
  3. 将十六进制摘要包含在头部中,例如 X-Signature: sha256=...。
  4. 发送 POST 请求。
// 使用 crypto 的 Node.js 示例
const crypto = require('crypto');
const secret = 'your_shared_secret';
const payload = JSON.stringify({ event: 'payment.success', amount: 100 });
const signature = crypto.createHmac('sha256', secret).update(payload).digest('hex');
// 发送 POST 请求,头部包含 X-Signature: sha256=signature

验证签名

在接收方,提取签名头部,计算原始请求体的 HMAC,并使用恒定时间比较来防止时序攻击。

// Express.js 示例
app.post('/webhook', (req, res) => {
  const signature = req.headers['x-signature'];
  const computed = crypto.createHmac('sha256', secret).update(req.rawBody).digest('hex');
  if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(computed))) {
    return res.status(401).send('Invalid signature');
  }
  // 处理载荷
  res.status(200).send('OK');
});

注意:确保使用原始请求体,而不是解析后的 JSON,因为解析可能会改变载荷。

防止重放攻击

在签名载荷中包含时间戳,并拒绝超过几分钟的请求。同时,包含唯一的事件 ID 并存储已处理的 ID 以避免重复。

可靠交付的重试逻辑

Webhook 端点可能宕机或响应缓慢。实现带有指数退避和抖动的重试。设置最大重试次数(例如 5 次)和每个请求的超时时间。

重试策略

示例重试计划:第 1 次重试在 5 秒后,第 2 次在 30 秒后,第 3 次在 2 分钟后,第 4 次在 10 分钟后,第 5 次在 1 小时后。

处理失败

如果所有重试都失败,记录失败并通知订阅者(例如通过电子邮件或仪表板)。提供手动重新发送 Webhook 的方式。

比较:签名载荷 vs. 基本认证

方法 安全性 复杂性 重放保护
HMAC 签名载荷 高 中等 是(带时间戳)
基本认证 低 低 否
头部中的 API 密钥 中 低 否

最佳实践

常见问题

如何验证 Webhook 签名?

使用你的密钥计算原始请求体的 HMAC,并使用恒定时间比较将其与签名头部进行比较。

如果 Webhook 失败,我该怎么办?

实现带有指数退避和抖动的重试。如果所有重试都失败,记录失败并提供手动重新发送选项。

我可以不使用签名而使用 Webhook 吗?

不建议这样做。没有签名,你无法验证发送方,使你的系统容易受到欺骗和重放攻击。

在测试 Webhook 载荷时,你可能需要检查 JSON 响应。使用我们的 JSON Formatter 快速美化打印和验证 JSON 数据。