SuperAPI AI 工具集

webhook-security

安全与审计

查看项目

更新于 10-15 08:43

技能介绍

用途

webhook-security 用于加固支付类 Webhook 端点,防止三类最常见的安全问题:竞态条件(重复入账)、重放攻击和时序攻击。它面向使用 Xendit、Stripe、Paddle 以及通用 Webhook 的场景,帮助开发者以较低成本让支付回调具备幂等性和时序安全性。

三类漏洞与处理方式

1. TOCTOU 竞态条件(重复入账)

问题在于“先查后写”:先 SELECT 判断 Webhook 是否已处理,再执行 INSERT 与 UPDATE。两个并发请求可能都在任一方提交前通过 SELECT,从而各自入账一次。

资料给出的处理方式是改为原子化幂等写入:使用 INSERT OR IGNORE,利用 ref 列上的 UNIQUE 约束保证原子性。若两个请求同时到达,只有一个 INSERT 成功(changes === 1),另一个得到 changes === 0 并提前返回成功、不再入账。只有 INSERT 成功后才执行额度增加。

2. 令牌校验的时序攻击

问题在于使用 === 或 !== 比较令牌,会通过响应耗时泄漏正确令牌的信息。

处理方式是使用时序安全比较:先比较字节长度,若不同直接返回 false;随后对每个字节做 XOR 并累积 mismatch,始终遍历全部字节,最后以 mismatch 是否为 0 判断相等。资料同时强调在比较前要检查 expectedToken 与 callbackToken 是否存在。

3. 重放攻击(缺少幂等)

问题在于没有去重,导致同一 Webhook 被多次处理。处理方式是始终存储唯一引用(external_id、invoice_id)并加上数据库 UNIQUE 约束,配合前述 INSERT OR IGNORE 模式自动完成去重。

完整处理器流程

资料提供了一个完整的 POST 处理器模板,顺序如下:

  1. 生成请求 ID,使用时序安全方式校验 x-callback-token,失败记录审计日志并返回 403。
  2. 解析并校验载荷结构,失败返回 400。
  3. 跳过非 PAID 状态的事件,返回 200。
  4. 校验 credits 与预期套餐一致(纵深防御),不一致返回 400。
  5. 执行原子幂等入账(INSERT OR IGNORE);若 changes === 0 视为重复并返回 200;否则更新用户额度并记录审计日志。
  6. 异常时记录审计日志并返回 500。

数据库结构要求

资料要求交易表包含 user_id、amount、reason、引用字段(如 xendit_ref)和 created_at,并对引用字段建立 UNIQUE 约束,这是幂等性的关键;同时建议为 user_id 建立索引、为引用字段建立唯一索引。

服务商差异

  • Xendit:令牌头为 x-callback-token,使用静态共享密钥(非 HMAC),对 5xx 响应会重试。
  • Stripe:令牌头为 stripe-signature,对请求体做 HMAC-SHA256 签名,使用 stripe.webhooks.constructEvent() 校验。
  • Paddle:令牌头为 paddle-signature,带时间戳的 HMAC-SHA256,使用 Paddle SDK 校验。

测试方式

资料给出示例测试:用同一 invoice 引用重复调用,第一次应入账、第二次不应重复入账(额度仍为 1);使用错误令牌应返回 403。

适用场景与限制

适用于需要防止支付回调重复入账、令牌被时序探测以及重放的处理场景,尤其是涉及 Xendit、Stripe、Paddle 的支付系统。限制方面,资料未说明具体支持的运行环境、依赖版本、性能开销或与其他框架的集成细节,这些信息暂未提供;实际使用时应结合自身技术栈与数据库能力调整。