Webhook 端点是外部可访问的输入边界。合理的 JSON 主体并不能证明提供者发送了它,有效的签名也不一定证明它是新的。在设计和测试中单独的传输保护、有效负载身份验证和重放处理。
验证提供商的实际签名方案
使用 HTTPS 和提供商记录的签名算法。在解析或规范化之前保留原始请求正文以进行签名验证。将机密存储在批准的机密系统中,并避免将其打印在日志中。如果验证失败或缺少所需的标头,则拒绝输入而不应用其请求的效果。
GitHub 的 webhook 验证指南 在 X-Hub-Signature-256 中记录了 HMAC SHA-256 签名,并建议进行安全比较而不是普通的相等。这是具体的参考实现边界。其他提供商可能会签署时间戳、选定的标头或不同的规范字符串,因此请勿原封不动地传输 GitHub 配方。
分别对待新鲜度和身份
GitHub 的 webhook 最佳实践 建议使用 X-GitHub-Delivery 来识别交付,并注意请求的重新交付保留原始交付 ID。保留适用于相关订阅或安装的重复数据删除记录。重新投递应修复处理,而不是创建第二张票证或更改。
仅正文签名不会验证任意传递标头。攻击者使用更改后的未签名传递 ID 重放捕获的签名字节可以逃避仅 ID 重复数据删除。未签名的时间戳同样不能证明新鲜度。将交付 ID 指导视为对此信任边界的一种控制,而不是加密重放保证。不要发明 GitHub 签名时间戳标头。如果提供商签署了时间戳,请根据提供商记录的容忍度进行验证,并 规范化 规则。 Where it does not, delivery identity and controlled deduplication are important but have limits: an event replayed after identity retention expires may no longer be recognizable.设置和记录保留时要考虑到该风险。
比较两种重播情况
假设原始 GitHub 交付具有有效的正文签名和已处理的交付 ID。请求的重新传递会保留该 ID,从而允许接收者找到其记录的状态并避免重复该效果。现在假设捕获的签名主体字节以不同的未签名传递 ID 到达。主体验证仍然可以成功,因为该标头位于签名主体之外;仅 ID 重复数据删除并不足以提供新鲜度的加密证明。这些是假设的推理案例,而不是执行的攻击或提供商的交付。
For a cooperating sender whose documented scheme authenticates an event identity and timestamp together with the payload, test tampering, genuinely signed expired timestamps, future timestamps outside the allowed tolerance and repeated identities.不要为不提供这种方案的提供商发明这样的方案。这里不提供自定义信封、签名密钥或重放测试。精确的身体指纹可能有助于调查重复,但相同的有效负载也可以代表不同的合法事件;定义业务身份和接受规则,而不是不加区别地丢弃所有平等主体。
限制已接受事件的后果
验证后,验证事件类型、操作、架构和租户映射。将可信订阅绑定到预期租户,而不是接受正文中的任意租户 ID。以稳定的身份排队接受工作,并将配置更改保留在其正常批准边界之后。经过身份验证的 Webhook 无需被授权更改DNS即可报告事件。
记录验证结果、交付身份、接收时间和安全证据参考,同时最大限度地减少有效负载保留。当租户关联或签名状态不明确时停止处理。恢复应通过相同的受保护路径重播保留的已验证事件,而不是绕过验证来清除队列。本指南不验证EmailAuth Webhook 集成或任何真实提供商交付。