近日,站长圈内广泛使用的 AI 大模型接口聚合管理系统 QuantumNous/new-api(简称 NewAPI)被证实存在一项高风险的支付逻辑漏洞。当系统未正确配置 Stripe 支付密钥时,攻击者可通过伪造 Webhook 事件,绕过真实的支付流程,实现“零成本”的任意金额充值。很多使用该系统的都出现很多已支付订单,但实际该订单并未支付,查看运行日志均显示正常,下如图

第一步:先止血(禁用/api/stripe/webhook),再修复
方式A:Nginx 直接拦截(最快)
location = /api/stripe/webhook {
return 403;
}
然后:
nginx -t && nginx -s reload
再访问 你的网址https://你的网址/api/stripe/webhook 应该出现403状态
排查并清理已被伪造的订单(很重要)
如果已经出现异常充值,必须做这几步:
- 冻结该时段充值权益(避免继续消费被盗刷余额)
- 导出异常订单:筛选
pay_method=stripe且webhook入账、无真实charge/payment_intent - 回滚用户余额 / 配额(按订单号逐单冲正)
- 记录审计日志(用户ID、订单号、IP、UA、时间)
- 强制轮换:
- Stripe Secret Key
- Webhook Signing Secret
- 站点管理后台密钥(如有泄露风险)
正式修复
必须同时满足,缺一不可:
- 未配置 Stripe Secret Key / Webhook Secret 时,webhook 必须拒绝(403/500)
- 使用
Stripe-Signature+ 官方库ConstructEvent验签 - 校验事件类型仅允许白名单(如
checkout.session.completed) - 充值金额不能信任 webhook 里的 amount_total,必须按你系统内订单金额校验
- 校验
session.id / payment_intent / client_reference_id(order_no)与本地订单一致 - 订单幂等(同一 event.id 只能处理一次;同一订单只能支付成功一次)
- 仅在订单状态为
pending时可置paid - 记录原始 payload + signature + event_id 方便审计
关键文件漏洞点
controller/topup_stripe.go
这版代码的核心问题是:
endpointSecret := setting.StripeWebhookSecret可能为空- 空 secret 下仍继续
ConstructEventWithOptions,可能被伪造事件绕过(取决于库行为/配置) sessionCompleted里直接model.Recharge(referenceId, customerId),没有二次向 Stripe 核验 session/payment 实际支付状态与金额
把 StripeWebhook 改成严格模式(最小改动版):
func StripeWebhook(c *gin.Context) {
// 1) 必须配置密钥,否则拒绝
if strings.TrimSpace(setting.StripeWebhookSecret) == "" || strings.TrimSpace(setting.StripeApiSecret) == "" {
log.Println("Stripe webhook rejected: missing Stripe secrets")
c.AbortWithStatus(http.StatusForbidden)
return
}
payload, err := io.ReadAll(c.Request.Body)
if err != nil {
log.Printf("解析Stripe Webhook参数失败: %v\n", err)
c.AbortWithStatus(http.StatusBadRequest)
return
}
signature := c.GetHeader("Stripe-Signature")
if strings.TrimSpace(signature) == "" {
log.Println("Stripe webhook rejected: missing Stripe-Signature")
c.AbortWithStatus(http.StatusBadRequest)
return
}
event, err := webhook.ConstructEvent(payload, signature, setting.StripeWebhookSecret)
if err != nil {
log.Printf("Stripe Webhook验签失败: %v\n", err)
c.AbortWithStatus(http.StatusBadRequest)
return
}
switch event.Type {
case stripe.EventTypeCheckoutSessionCompleted:
sessionCompleted(event)
case stripe.EventTypeCheckoutSessionExpired:
sessionExpired(event)
default:
log.Printf("忽略不支持事件: %s\n", event.Type)
}
c.Status(http.StatusOK)
}
先禁用 Stripe webhook
controller/topup_stripe.go
func StripeWebhook(c *gin.Context) {
c.AbortWithStatus(http.StatusForbidden)
return
}
把 sessionCompleted 先改成这样(安全基础版)
func sessionCompleted(event stripe.Event) {
customerId := event.GetObjectValue("customer")
referenceId := event.GetObjectValue("client_reference_id")
status := event.GetObjectValue("status")
if referenceId == "" {
log.Println("Stripe回调缺少referenceId")
return
}
if status != "complete" {
log.Println("错误的Stripe Checkout完成状态:", status, ",", referenceId)
return
}
// 本地订单校验
topUp := model.GetTopUpByTradeNo(referenceId)
if topUp == nil {
log.Println("Stripe回调订单不存在:", referenceId)
return
}
if topUp.PaymentMethod != PaymentMethodStripe {
log.Println("Stripe回调支付方式不匹配:", referenceId)
return
}
if topUp.Status != common.TopUpStatusPending {
log.Println("Stripe回调订单非待支付状态(幂等拦截):", referenceId, "status=", topUp.Status)
return
}
err := model.Recharge(referenceId, customerId)
if err != nil {
log.Println("Stripe充值处理失败:", err.Error(), referenceId)
return
}
total, _ := strconv.ParseFloat(event.GetObjectValue("amount_total"), 64)
currency := strings.ToUpper(event.GetObjectValue("currency"))
log.Printf("收到款项:%s, %.2f(%s)", referenceId, total/100, currency)
}
处理完上面代码这能马上阻断伪造回调入账。
漏洞原理剖析
NewAPI 是一款支持 OpenAI、Claude 等大模型接口中转、计费和充值等功能的管理系统。此次曝光的漏洞核心,在于其支付成功回调(Webhook 异步处理逻辑)缺失了对空密钥的严格校验。
根据技术社区流传的攻击流程分析,当服务器端的 Stripe webhook_secret 未配置(即为空字符串)时,会引发极其严重的信任危机:
- 签名机制失效:HMAC-SHA256算法在处理空密钥时不会报错。这意味着,任何攻击者都可以对自定义的 payload,计算出与服务端验证逻辑完全一致的伪造签名。
- 构造恶意事件:攻击者只需获取或猜测到订单号格式,便可伪造一个
checkout.session.completed(支付完成)事件,并在数据包中自定义极高的amount_total(充值金额)。 - 资金虚空增加:向服务端的 Webhook 端点发送该伪造请求后,服务端会使用空密钥进行验签。验签通过后,系统会误认为这是一笔真实的已支付订单,从而为攻击者账户充值。
最终结果是:Stripe 实际收款为 $0,Stripe 官方后台也无任何交易记录,但服务端的日志会显示正常的 Webhook 回调,且攻击者的账户余额被成功增加。
漏洞影响范围
该漏洞仅影响未正确配置 Stripe Secret Key 的实例。许多站长在搭建测试环境,或者站点主要依赖其他支付方式(如微信、支付宝)而闲置 Stripe 模块时,往往会忽略配置该密钥,从而极易中招。
官方修复与应对建议
针对这一严重的安全隐患,项目官方反应迅速,已于今日发布了最新的 v0.12.10 版本。更新日志中明确指出了修复方向:“Improved Stripe payment processing to better handle asynchronous webhook events”(改进 Stripe 支付处理以更好地处理异步 Webhook 事件),从底层修复了回调校验的安全盲区。
安全专家对所有使用 NewAPI 的站长提出以下强烈建议:
- 立即升级版本:尽快将实例升级至最新的 v0.12.10或更高版本(建议直接拉取最新 release 或 nightly 版本)。
- 强制配置密钥:即便你的站点不打算使用 Stripe 收款,升级后也务必在后台配置好 Stripe Secret Key。建议填入随机生成的强密码字符串,或通过环境变量严格控制,杜绝空密钥的存在。
- 开展账单自查:立即审查系统现有的用户订单和充值记录(尤其是测试环境),比对实际到账资金,排查是否存在虚假的高额充值。
- 完善支付鉴权:对于生产环境,建议全面检查所有支付渠道的异步回调逻辑,确保签名验证和订单状态的双重有效性校验。
目前,该漏洞的原理已在互联网上处于公开状态。由于其实际利用门槛较低,建议所有相关站长立刻采取行动进行自查与升级,以免造成数字资产的损失。


评论(0)