You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

如何关联Stripe Token与购买商品并防伪造?后端验证方法咨询

如何验证Stripe Token与对应商品的匹配性

首先得纠正一个常见误解:Stripe的支付方式Token(比如tok_xxx这类信用卡Token)本身不包含金额信息——金额是后端在发起扣款时指定的。所以你的问题本质是:如何防止前端篡改购买的商品/金额,确保后端扣款的金额是对应商品的正确价格,而不是用户伪造的数值。

下面给你两种解决方案,第一种适配你当前的Token流程,第二种是Stripe官方推荐的更安全的方案:

方案一:改进现有Token流程(适配你的当前场景)

如果暂时不想重构流程,可以通过以下步骤堵住安全漏洞:

  • 前端只传商品ID,别传金额:用户选完商品B后,前端只把商品的唯一标识(比如prod_b123)和支付Token传给后端,绝对不要让前端传金额——不然用户很容易把1000改成10,用合法Token扣走低价。
  • 后端自己算正确金额:后端根据前端传的商品ID,从你的数据库/配置里取出商品B的价格(1000美元),自己计算订单总金额(注意Stripe用最小单位,1000美元要转成100000 cents)。
  • 验证Token有效性:调用Stripe的stripe.tokens.retrieve(token_id)接口,确认这个Token是有效的支付方式(比如类型是card,状态正常,没有被用过)。
  • 用后端计算的金额发起扣款:调用stripe.charges.create()时,金额参数用你后端算出来的100000,而不是任何前端传来的数值。比如:
    const charge = await stripe.charges.create({
      amount: 100000,
      currency: 'usd',
      source: token_id,
      description: '购买商品B'
    });
    
  • 可选额外校验:如果前端非要传金额,后端可以对比前端数值和自己计算的是否一致,不一致直接拒绝请求。

这个方案的核心就是:后端完全掌控金额计算,绝不信任前端传来的金额,从根源上避免篡改。

方案二:使用Stripe Checkout Session(强烈推荐,更安全)

这是Stripe现在主推的集成方式,完全规避前端篡改的可能——因为整个支付会话是后端创建的,绑定了固定的商品和金额,前端只能跳转过去,没法改任何参数。

步骤如下:

  1. 前端请求创建会话:用户选完商品B后,前端把商品ID传给后端,请求生成Checkout会话。
  2. 后端创建绑定商品的会话
    如果你还没在Stripe后台创建商品价格,可以直接在代码里定义:
    const session = await stripe.checkout.sessions.create({
      payment_method_types: ['card'],
      line_items: [
        {
          price_data: {
            currency: 'usd',
            product_data: { name: '商品B' },
            unit_amount: 100000 // 1000美元,最小单位
          },
          quantity: 1
        }
      ],
      mode: 'payment',
      success_url: 'https://你的域名.com/payment-success',
      cancel_url: 'https://你的域名.com/payment-cancel'
    });
    
    要是已经在Stripe后台创建了商品价格,直接用价格ID更方便:
    line_items: [
      {
        price: 'price_xxx', // 商品B在Stripe的价格ID
        quantity: 1
      }
    ]
    
  3. 前端跳转至Stripe支付页:后端把生成的Session ID返回给前端,前端调用stripe.redirectToCheckout({ sessionId: session.id }),用户会被带到Stripe的安全支付页面。
  4. 后端通过Webhook确认支付:用户付完钱后,Stripe会主动给你预先配置的Webhook URL发送checkout.session.completed事件。后端要做两件事:
    • 验证Webhook签名:防止有人伪造支付成功通知,代码示例:
      const sig = req.headers['stripe-signature'];
      const event = stripe.webhooks.constructEvent(
        req.body,
        sig,
        process.env.STRIPE_WEBHOOK_SECRET // 从Stripe后台获取的Webhook密钥
      );
      
    • 校验订单信息:从事件里取出会话详情,确认amount_total是100000 cents,payment_statuspaid,然后在你的系统里创建订单、标记为已支付。

这种方案的优势很明显:所有核心逻辑都在后端,前端碰不到金额和商品配置;Stripe负责支付页的安全,你不用操心PCI合规;Webhook事件是Stripe主动推送的,支付状态绝对真实。

关键提醒

  • 不管用哪种方案,永远不要信任前端传来的金额,所有价格计算必须基于你后端存储的商品数据。
  • Webhook签名验证一定要做,不然很容易被人伪造支付成功的请求。
  • 尽量用方案二,Token+Charge的流程是比较旧的方式,Stripe现在更推荐用Checkout Session或Payment Intent,功能更全也更安全。

内容的提问来源于stack exchange,提问作者Appleboy

火山引擎 最新活动