如何关联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现在主推的集成方式,完全规避前端篡改的可能——因为整个支付会话是后端创建的,绑定了固定的商品和金额,前端只能跳转过去,没法改任何参数。
步骤如下:
- 前端请求创建会话:用户选完商品B后,前端把商品ID传给后端,请求生成Checkout会话。
- 后端创建绑定商品的会话:
如果你还没在Stripe后台创建商品价格,可以直接在代码里定义:
要是已经在Stripe后台创建了商品价格,直接用价格ID更方便: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' });line_items: [ { price: 'price_xxx', // 商品B在Stripe的价格ID quantity: 1 } ] - 前端跳转至Stripe支付页:后端把生成的Session ID返回给前端,前端调用
stripe.redirectToCheckout({ sessionId: session.id }),用户会被带到Stripe的安全支付页面。 - 后端通过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_status是paid,然后在你的系统里创建订单、标记为已支付。
- 验证Webhook签名:防止有人伪造支付成功通知,代码示例:
这种方案的优势很明显:所有核心逻辑都在后端,前端碰不到金额和商品配置;Stripe负责支付页的安全,你不用操心PCI合规;Webhook事件是Stripe主动推送的,支付状态绝对真实。
关键提醒
- 不管用哪种方案,永远不要信任前端传来的金额,所有价格计算必须基于你后端存储的商品数据。
- Webhook签名验证一定要做,不然很容易被人伪造支付成功的请求。
- 尽量用方案二,Token+Charge的流程是比较旧的方式,Stripe现在更推荐用Checkout Session或Payment Intent,功能更全也更安全。
内容的提问来源于stack exchange,提问作者Appleboy




