Webhook 接入第三方服务时,最容易漏掉的 6 个保护点

Webhook 接入第三方服务时,最容易漏掉的 6 个保护点

Webhook 看起来像一件很轻的事: 给第三方一个回调地址,等它推数据过来就行。很多项目第一次接支付通知、短信回执、工单系统、AI 任务完成回调时,都是这么开始的。

但真到线上,Webhook 是很容易出问题的一类入口。它不像普通前端请求那样可控,也不像内部服务调用那样有统一环境。只要少做几个保护点,后面就很容易出现重复处理、伪造请求、超时重试和脏数据写入。

第一个保护点:不要默认“收到就是可信的”

很多项目拿到 Webhook 后第一时间就直接开始解析业务字段,这其实很危险。

更稳的顺序应该是:

  1. 先校验来源
  2. 再校验签名
  3. 再校验时间戳
  4. 最后才进入业务处理

如果一开始就把请求体当可信数据,后面哪怕只是写了一条状态更新,也可能留下安全口子。

第二个保护点:签名校验别只做“有就行”

做签名校验时最常见的问题有两个:

  1. 只比对字段,不比对原始载荷
  2. 签名通过后没有检查时间窗口

更稳的做法通常是:

  1. 基于原始请求体参与签名计算
  2. 使用固定算法和共享密钥
  3. 限制签名有效时间
  4. 校验失败立即返回,不进入业务逻辑

如果签名只做了半套,看起来像做了安全,实际拦不住很多问题。

第三个保护点:幂等一定要有

第三方 Webhook 重复推送非常常见,不一定是对方有问题,有时候只是网络波动、超时重试、或者你返回结果不够快。

所以你最好默认同一事件至少会来两次甚至更多次。

更适合的处理方式通常是:

  1. 提取事件唯一 ID
  2. 在本地做幂等记录
  3. 已处理过就直接返回成功
  4. 不要重复执行业务写操作

如果没有幂等,支付回调、库存更新、消息下发这类流程最容易出事故。

第四个保护点:快速确认,异步处理

Webhook 入口最忌讳的一件事,就是把所有业务都在回调里同步做完。

因为你一旦处理太慢,就会遇到:

  1. 第三方认定超时
  2. 对方继续重试
  3. 你的服务开始重复处理
  4. 整个链路越滚越乱

更稳的方式通常是:

  1. 入口先完成校验
  2. 记录原始事件
  3. 快速返回成功或已接收
  4. 后续异步消费执行业务

这样即使后面的处理偶尔失败,你也还有补偿和重试空间。

第五个保护点:原始请求体要留档

很多人只存解析后的字段,不存原始请求体。等线上出问题时,排查会非常被动,因为你根本不知道第三方当时真实推了什么。

我更倾向至少保留:

  1. 请求头
  2. 原始 body
  3. 接收时间
  4. 校验结果
  5. 处理结果

这样后面遇到签名争议、字段缺失、重复推送时,才有东西可追。

第六个保护点:错误返回要有策略

Webhook 不是所有错误都应该返回失败。

例如:

  1. 请求非法、签名不对,应该明确拒绝
  2. 已处理过的重复事件,通常应该返回成功
  3. 临时内部错误,才考虑让对方重试

如果所有异常都直接返回 500,对方就会不断重试,本来一次问题会被放大成很多次问题。

日志和告警不能缺

Webhook 的可怕之处在于,很多问题不是立刻爆炸,而是悄悄累积。例如:

  1. 某个供应商签名字段改了
  2. 某批事件推送大量失败
  3. 某条异步消费链卡住
  4. 重复通知突然明显增多

所以你最好至少有这些监控:

  1. 接收量
  2. 校验失败量
  3. 幂等命中量
  4. 处理失败量
  5. 平均响应时间

没有这些指标,Webhook 出问题时通常只能靠用户先来告诉你。

一个更适合中小项目的落地模型

如果你准备接第三方回调,我更建议按这个顺序建设:

  1. 入口层做来源校验、签名校验、时间窗口校验
  2. 落库存原始事件
  3. 基于事件 ID 做幂等
  4. 业务异步消费
  5. 建立重试、补偿和告警

这套结构并不算重,但已经能覆盖大多数中小项目的实际风险。

结语

Webhook 难的从来不是“能接到”,而是“接到之后能不能稳”。只要把信任校验、幂等、异步化和可追踪性这几层补齐,第三方回调就不会只是一个脆弱入口,而会变成一条可维护的业务链路。

对个人项目和中小系统来说,这几步比单纯把接口通了更重要。