
联系逍遥
扫码添加微信,或点击下方按钮复制联系方式。
进微信群请联系博主,各位觉得文章对你有帮助的话可否打赏一些呀~
⚠️ 时效性提醒(2026-07 更新):该漏洞已在 newapi v0.12.10 中修复。如果你正在使用 newapi,请确认已升级到修复版本。本文保留仅供支付安全设计参考。
漏洞概述
2026 年 4 月 16 日,LINUX DO 社区用户披露了 newapi 项目中的一个严重充值漏洞。攻击者可在未配置 Stripe 密钥的情况下,通过伪造签名绕过支付验证,实现零成本任意金额充值。
影响版本:v0.12.10 之前 修复版本:v0.12.10 漏洞类型:签名验证绕过 / 支付逻辑缺陷 风险等级:🔴 严重(直接资金损失)
攻击流程详解
第一阶段:信息收集
1. 发现目标暴露了 Stripe Webhook 端点 /api/stripe/webhook
2. 通过初始审计(或黑盒探测)确认服务端使用了空的 StripeWebhookSecret
3. 获取或猜测 client_reference_id 的格式(如 USR + 数字 + 随机字符串 + 时间戳)
攻击者首先识别出目标的 Webhook 端点,并探测到服务端未正确配置 webhook_secret(空字符串)。这是漏洞利用的关键前提。
第二阶段:伪造签名
Stripe 的签名机制:
signed_payload = "{timestamp}.{json_body}"
v1 = HMAC-SHA256(webhook_secret, signed_payload)
Header = "t={timestamp},v1={v1}"
当 webhook_secret = “"(空字符串)时:
- HMAC-SHA256 不会报错,正常计算
- 任何人都能对任意 payload 算出与服务端一致的签名
- 服务端调用
webhook.ConstructEventWithOptions()验签 → 通过 ✅
这是整个漏洞的核心:空密钥仍能通过 HMAC 计算,导致签名验证形同虚设。
第三阶段:构造恶意事件
伪造一个 checkout.session.completed 事件:
{
"type": "checkout.session.completed",
"data": {
"object": {
"client_reference_id": "目标用户/订单 ID",
"status": "complete",
"payment_status": "paid",
"amount_total": 任意金额
}
}
}
攻击者可指定任意 client_reference_id 和 amount_total,实现定向充值和任意金额。
第四阶段:发送请求
向 Webhook 端点发送带有伪造签名的 POST 请求,服务端处理流程:
收到请求
↓
用空密钥验签 → 通过 ✅
↓
解析事件类型 → checkout.session.completed
↓
读取 client_reference_id 查找订单
↓
标记订单已支付,给用户充值
第五阶段:结果
| 项目 | 说明 |
|---|---|
| 用户余额 | 被充入攻击者指定的金额 |
| Stripe 实际收款 | $0(从未发生真实支付) |
| Stripe Dashboard | 无对应交易记录 |
| 服务端日志 | 看起来像正常的 Webhook 回调 |
技术原理分析
为什么空密钥能通过验签?
HMAC-SHA256 算法本身不验证密钥长度。当密钥为空字符串时:
import hmac
import hashlib
# 空密钥仍能计算
signature = hmac.new(
b"", # 空密钥
b"timestamp.body",
hashlib.sha256
).hexdigest()
# 结果:有效的 64 字符十六进制字符串
服务端代码若未检查 webhook_secret 是否为空,就会用空密钥验签,导致攻击者可以:
- 获取相同的 payload
- 用空密钥计算相同的签名
- 伪造出"合法"的请求
正确的防御姿势
# ❌ 错误:未检查密钥是否为空
if not webhook_secret:
webhook_secret = "" # 危险!
# ✅ 正确:强制要求配置密钥
if not webhook_secret or len(webhook_secret) < 32:
raise ConfigurationError("Stripe webhook secret must be configured")
影响范围
直接受影响
- 所有使用 newapi v0.12.10 之前版本
- 未配置或错误配置
StripeWebhookSecret的实例 - 依赖 Stripe Webhook 进行充值确认的业务
潜在风险
- 资金损失:攻击者可零成本获取服务额度
- 数据污染:虚假交易记录污染财务数据
- 合规风险:支付审计无法通过
修复建议
立即措施
- 升级版本:立即升级到 v0.12.10 或更高版本
- 检查配置:确认
StripeWebhookSecret已正确配置(非空) - 审计日志:检查历史 Webhook 记录,排查异常充值
长期加固
- 启动检查:服务启动时强制验证关键配置项
- 签名验证增强:除 HMAC 外,增加时间戳窗口校验
- 对账机制:定期与 Stripe Dashboard 对账,发现不一致立即告警
- 监控告警:对大额充值、频繁充值设置阈值告警
代码修复示例
v0.12.10 的修复逻辑(推测):
// 修复前
func (s *Service) VerifyWebhook(payload []byte, signature string) (*Event, error) {
secret := s.config.StripeWebhookSecret // 可能为空
event, err := webhook.ConstructEvent(payload, signature, secret)
return &event, err
}
// 修复后
func (s *Service) VerifyWebhook(payload []byte, signature string) (*Event, error) {
if s.config.StripeWebhookSecret == "" {
return nil, errors.New("stripe webhook secret not configured")
}
event, err := webhook.ConstructEvent(payload, signature, s.config.StripeWebhookSecret)
return &event, err
}
总结
这是一个典型的配置缺陷 + 逻辑漏洞组合:
- 配置缺陷:允许空密钥存在
- 逻辑漏洞:未验证密钥有效性即进行签名计算
教训:安全配置项必须在上层进行有效性校验,不能依赖底层库的"隐式行为”。空字符串不是"未配置",而是"配置了空值"——这两者有本质区别。
参考资料
本文基于社区披露信息进行分析,仅供安全研究参考。请合法合规使用,未经授权不得对任何系统进行测试。
