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

20260417145637624

第一步:先止血(禁用/api/stripe/webhook),再修复

方式A:Nginx 直接拦截(最快)

location = /api/stripe/webhook {
return 403;
}

然后:

nginx -t && nginx -s reload

再访问 你的网址https://你的网址/api/stripe/webhook 应该出现403状态

排查并清理已被伪造的订单(很重要)

如果已经出现异常充值,必须做这几步:

  1. 冻结该时段充值权益(避免继续消费被盗刷余额)
  2. 导出异常订单:筛选 pay_method=stripe 且 webhook入账无真实charge/payment_intent
  3. 回滚用户余额 / 配额(按订单号逐单冲正)
  4. 记录审计日志(用户ID、订单号、IP、UA、时间)
  5. 强制轮换:
    • 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

这版代码的核心问题是:

  1. endpointSecret := setting.StripeWebhookSecret 可能为空
  2. 空 secret 下仍继续 ConstructEventWithOptions,可能被伪造事件绕过(取决于库行为/配置)
  3. 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 未配置(即为空字符串)时,会引发极其严重的信任危机:

  1. 签名机制失效:HMAC-SHA256算法在处理空密钥时不会报错。这意味着,任何攻击者都可以对自定义的 payload,计算出与服务端验证逻辑完全一致的伪造签名。
  2. 构造恶意事件:攻击者只需获取或猜测到订单号格式,便可伪造一个 checkout.session.completed(支付完成)事件,并在数据包中自定义极高的 amount_total(充值金额)。
  3. 资金虚空增加:向服务端的 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。建议填入随机生成的强密码字符串,或通过环境变量严格控制,杜绝空密钥的存在。
  • 开展账单自查:立即审查系统现有的用户订单和充值记录(尤其是测试环境),比对实际到账资金,排查是否存在虚假的高额充值。
  • 完善支付鉴权:对于生产环境,建议全面检查所有支付渠道的异步回调逻辑,确保签名验证和订单状态的双重有效性校验。

目前,该漏洞的原理已在互联网上处于公开状态。由于其实际利用门槛较低,建议所有相关站长立刻采取行动进行自查与升级,以免造成数字资产的损失。

服务声明: 本网站除正版商用版块可商用外,其他所有发布的源码、软件和资料均为作者提供或网友推荐收集各大资源网站整理而来,仅供功能验证和学习研究使用,您必须在下载后24小时内删除。不得使用于非法商业用途,不得违反国家法律,否则后果自负!一切关于该资源商业行为与本站无关。如果您喜欢该程序,请支持购买正版源码,得到更好的正版服务。如有侵犯你的版权合法权益,请邮件或QQ:3089659733与我们联系处理删除(邮箱:ynzsy@qq.com),本站将立即更正。