技术解析 · 附来源的解答

Webhook 签名验证

Webhook 签名验证是一种安全流程:接收方校验附加在传入 HTTP 请求上的加密签名,以确保负载确实由可信的服务商发送,并且在传输过程中未被篡改。

定义

Webhook 签名验证是一种用于验证 Webhook 事件来源的机制。当 Resend 或 SendGrid 等服务商发送邮件事件通知时,会附上一个用密钥签名的负载哈希。接收方服务器使用同一个密钥重新计算哈希,并将其与请求头中提供的签名进行比较。

工作流程

服务商使用共享密钥和请求体生成 HMAC 哈希,并通过一个请求头发送,该请求头通常名为 X-Signature 或类似名称。接收方获取原始请求体和签名请求头,然后使用共享密钥计算自己的 HMAC 哈希。如果计算出的哈希与请求头中的值一致,该请求就是真实的;如果不一致,该请求将作为未授权请求被拒绝。

对发件人的重要性

如果不进行验证,任何知道您 Webhook URL 的人都可以向您的服务器发送伪造的数据。这可能导致错误的数据库更新,例如把一封已送达的邮件标记为退信。实施签名验证可以防止伪造攻击,并确保您的应用只对由您的邮件基础设施触发的合法事件作出响应。

运维说明

一个常见错误是在验证签名之前就把请求体解析成 JSON 对象。由于 JSON 解析器可能会改变空白字符或键的顺序,得到的字符串可能与服务商所用的原始负载不一致。请始终使用未经解析的原始请求体计算 HMAC,以免验证失败。

实现示例

在 Node.js 环境中,开发者会使用 crypto 模块,以服务商密钥对原始请求体计算 hmac sha256 哈希,然后使用常量时间比较函数将结果与签名请求头进行比较,以防御时序攻击。SendHQ 在 https://sendhq.cc/tools 提供免费工具,帮助您管理在设置 Webhook 之前通常需要完成的各项邮件配置。

团队常问的问题

如果密钥泄露了会怎样?

如果密钥泄露,攻击者就可以对伪造的请求进行签名,而您的服务器会将其视为有效请求。您必须立即在服务商控制台中轮换密钥,并更新服务器的环境变量。

有了 HTTPS 还需要签名验证吗?

需要。HTTPS 会加密传输中的数据并验证服务器身份,但无法验证发送请求的具体客户端就是您授权的邮件服务商。

为什么使用 HMAC 而不是简单的 API 密钥?

HMAC 签名可以证明邮件内容未被篡改。请求头中的静态 API 密钥只能证明发送方知道该密钥,而不能证明负载完好无损。

一手资料