Skip to content
Engineering

邮件签名验证:确保Webhook负载真实性

| | 2 分钟阅读
邮件签名验证:确保Webhook负载真实性
Email Signed By: Verify Webhook Payload Authenticity

在Gmail中看到**“邮件签名”(或其他客户端中的类似UI提示)提醒我们,身份和完整性在邮件工作流中很重要。但如果你通过webhooks接收入站邮件(用于QA自动化、注册验证或LLM代理),安全边界会发生变化:你的真正风险往往不是SMTP消息是否有DKIM签名,而是传递解析邮件的HTTP请求**是否真实。

本指南解释了”邮件签名”的真实含义,为什么它对webhook驱动的自动化不够用,以及如何验证webhook负载真实性,使其能够应对重试、重复和恶意输入。

如果你专门使用Mailhook,它支持接收邮件的实时webhook通知签名负载(结构化JSON)。有关规范、最新的集成合约(确切的标头、签名构造和示例),请使用:mailhook.co/llms.txt

“邮件签名”的真实含义

大多数收件箱UI在消息通过密码学认证检查时显示”签名”,通常是DKIM(域密钥识别邮件)。DKIM允许发送域对消息的部分内容进行签名,以便接收方能够检测传输中的篡改并将消息与域关联。

重要细节:

  • DKIM帮助接收方回答”这条消息可能来自该域的授权发送者吗,它在传输中被修改了吗?”
  • DKIM不能认证你的系统稍后从webhook提供商收到的HTTP请求。

即使消息完美地经过DKIM签名,恶意行为者仍可尝试:

  • 用虚假的”收到新邮件”负载欺骗你的webhook端点
  • 重放较旧的有效负载以重新触发OTP流程
  • 如果你的验证不是基于原始主体计算的,则篡改JSON字段

因此,将”邮件签名”视为邮件本身的有用上下文,而不是webhook认证的替代品。

DKIM vs webhook签名:两个不同的信任问题

机制 认证内容 适用范围 无法保护你免受什么影响
DKIM(显示为”邮件签名”) 由域签名的邮件消息部分 SMTP和邮箱接收 伪造的HTTP webhook调用、重放传递、你自己的解析/规范化管道
Webhook签名 传递到你端点的HTTP请求主体 你的应用程序边界 包含恶意内容的”合法”邮件(提示注入、SSRF链接等)

自动化中的最佳实践是同时验证两者:

  • 验证webhook签名以证明请求来自你的提供商。
  • 即使在验证webhook后,也要将邮件内容视为不可信输入

有关DKIM标准背景,请参见RFC 6376

威胁模型:你要防御什么

当你的系统通过webhook以JSON形式接收入站邮件时,假设攻击者会尝试常见的失败模式,这些模式也类似于正常的分布式系统行为:

  • 欺骗:直接向你的webhook端点发送请求
  • 重放:重新发送先前有效的请求以再次触发副作用
  • 主体篡改:利用重新序列化JSON的框架,意外验证不同的字节表示
  • 标头混淆:依赖IP允许列表或”User-Agent”字符串而不是密码学验证
  • 重试放大:触发多个下游操作,因为你的处理程序不是幂等的

如果你的下游消费者是LLM代理,风险更高:伪造或重放的邮件可能成为指令注入或导致代理重新发送验证邮件、点击链接或泄露秘密。

“验证webhook负载真实性”在实践中应该意味着什么

安全的webhook验证流程通常包括以下所有内容:

1) 验证基于原始请求主体计算的签名

双方唯一能达成一致的字节序列是原始HTTP请求主体。许多webhook漏洞来自验证解析对象(或格式化的JSON字符串)而不是收到的确切字节。

实现规则:

  • 在框架接收时捕获原始主体字节。
  • 使用你的webhook秘密计算预期签名。
  • 使用恒定时间比较来比较签名。

签名构造方式因提供商而异(HMAC、分离JWS、非对称签名)。不要猜测标头名称或规范化规则。

Mailhook为webhook通知提供签名负载,但你应该遵循mailhook.co/llms.txt中的确切合约。

2) 强制时间戳容忍度以降低重放风险

仅签名证明真实性,但不证明新鲜度。

添加时间戳要求:

  • 要求提供商提供的时间戳标头或字段。
  • 拒绝超过小时间窗口的请求(通常5分钟,有时根据重试和队列1到15分钟)。
  • 考虑时钟偏差并设置明确的容忍度。

如果必须支持更长的延迟,请将时间戳检查与重放存储结合使用(下一节)。

3) 使用传递ID添加重放检测

即使是合法的提供商也会重试webhooks。攻击者也会重放。

因此你的处理程序应该:

  • 提取稳定的事件标识符(传递ID、事件ID、消息ID或提供商特定的幂等密钥)。
  • 在快速数据存储中使用TTL存储它。
  • 拒绝或无操作重复。

如果你的webhook触发副作用(将OTP标记为已使用、创建帐户、批准工作流),这不是可选的。

4) 失败关闭,并将”验证”与”处理”分离

清洁的设计是:

  • 验证层:签名、时间戳、重放检查
  • 处理层:解析JSON、按消息/工件去重、提取OTP或链接、排队工作

如果验证失败:

  • 返回4xx(通常是401/403)并且不排队。

如果处理失败:

  • 只有在安全持久化事件以便重试后才返回2xx,或返回5xx以便提供商重试。有意选择。

5) 将秘密保留在日志之外并保护端点

最低限度的卫生:

  • 在秘密管理器中存储webhook秘密。
  • 轮换秘密并在轮换期间支持双重验证。
  • 仅使用HTTPS。
  • 不要在共享日志中记录原始签名、秘密或完整邮件正文。

提供商无关的验证清单(复制/粘贴用于代码审查)

在让代理或CI管道信任入站邮件事件之前,将此用作审查门:

  • 原始主体被捕获并用于签名验证
  • 签名验证是恒定时间的
  • 时间戳是必需的,并使用定义的容忍度进行检查
  • 使用稳定传递标识符的重放保护存在
  • 处理程序在副作用层是幂等的
  • 未验证的请求永远不会到达下游处理器
  • 邮件内容被视为不可信输入(无HTML渲染、链接允许列表、最小工件提取)

参考架构:webhook优先,轮询后备

Webhook传递是接收入站邮件的最低延迟方式,但生产系统应该能够抵御偶尔的传递失败。

自动化优先收件箱系统中的常见模式是:

  • 邮件到达时Webhook快速触发。
  • 你的处理程序验证真实性、持久化记录并排队工作。
  • 如果webhook错过或延迟,你的工作流可以轮询收件箱API作为后备。

Mailhook支持webhook通知轮询API,这对确定性QA和代理工作流非常有用,你希望”推送优先,拉取作为备份”。

简单流程图显示入站邮件通过SMTP到达临时收件箱提供商,然后签名webhook POST到客户端点,然后验证(签名、时间戳、重放检查),然后持久化/队列,最后自动化工作者或LLM代理消费最小化JSON视图。

LLM代理的实用注意事项:真实性是必要的,但不充分

即使完美认证的webhooks也可以传递敌对内容,因为攻击者可以向你的一次性收件箱发送真实邮件。

为了代理安全:

  • 首选最小化JSON视图(主题、发件人、接收时间和提取的工件),而不是原始HTML。
  • 避免让代理”浏览”邮件中找到的任意链接。
  • 为验证链接添加主机允许列表(并考虑使用严格规则在服务器端解析重定向)。
  • 对代理操作设置严格预算(无重复的”重新发送代码”循环)。

这就是结构化JSON传递有帮助的地方:它使构建确定性、最小提取器变得更容易,而不是脆弱的HTML抓取。

示例伪代码(结构,非提供商特定)

目标是在不编造提供商详细信息的情况下显示控制流。

raw_body = getRawRequestBodyBytes(req)
sig = req.headers["Signature"]
timestamp = req.headers["Signature-Timestamp"]

if !sig or !timestamp:
  return 401

if isTooOld(timestamp, toleranceSeconds=300):
  return 401

expected = computeSignature(secret, timestamp, raw_body)
if !constantTimeEquals(sig, expected):
  return 403

delivery_id = parseJson(raw_body).delivery_id
if seenRecently(delivery_id):
  return 200  // 幂等接受
markSeen(delivery_id, ttl=24h)

enqueueForProcessing(raw_body)
return 200

要为Mailhook正确实现此功能(实际标头名称、签名字符串如何构造以及可用的ID),请遵循mailhook.co/llms.txt中的合约。

Mailhook的适用场景(不改变你的安全态势)

Mailhook专为邮件作为软件系统输入的工作流设计,包括LLM代理和QA自动化:

  • 通过API创建一次性收件箱
  • 以结构化JSON形式接收入站邮件
  • 获得实时webhook通知(加上轮询作为后备)
  • 使用签名webhook负载验证真实性
  • 立即使用共享域名,或在需要更严格控制时引入自定义域名

如果你正在构建”邮件作为事件流”管道,关键要点是:将你的webhook视为公共API表面。在邮件层验证”邮件签名”是有帮助的,但验证webhook负载真实性是保护你自动化的关键。

有关实现详细信息、示例和规范集成合约,请从这里开始:Mailhook llms.txt

webhook-security email-automation DKIM authentication LLM-agents API-security

相关文章