最近看到一篇关于“Figma 所有套餐 0 元购”的文章,核心说法是利用地区、SEPA 付款和 IBAN 信息去尝试开通付费套餐。这类内容不能当成教程传播,但它背后的安全问题值得认真复盘:为什么有些订阅系统会让人感觉“没真正付款也拿到了权益”?漏洞到底出在前端、支付方式,还是服务端状态机?

先声明:本文仅做安全学习和防护复盘,不提供真实网站绕过支付、伪造付款资料、滥用 SEPA/IBAN 或开通未授权订阅的操作步骤。下面的“实战”是本地模拟场景,目的是帮助开发者理解风险并修好自己的系统。

这类传闻的本质

网上流传的 Figma 0 元购思路,大致会围绕几个关键词展开:

  • 切换地区
  • 选择 SEPA 一类的银行扣款方式
  • 填写某种格式正确的 IBAN
  • 让系统先进入付费套餐状态

真正值得关注的不是某个工具或某个国家,而是这个问题:

订阅系统到底是在“用户提交了付款资料”时发放权益,还是在“支付真正成功并可结算”后发放权益?

如果系统在前者就发权益,就容易出现空窗期:用户还没有真实付款,甚至付款之后可能被拒付、退回、撤销,但业务侧已经把套餐升级了。

为什么 SEPA 类支付更容易被误解

银行卡支付通常会给人一种即时成功或失败的感觉,但银行扣款、借记、转账类支付在很多场景下不是这样的。它可能有几个阶段:

  • 创建付款意图
  • 收集付款资料
  • 等待银行处理
  • 扣款成功
  • 扣款失败
  • 退款或争议

如果 SaaS 系统只看到了“付款资料已提交”或者“支付流程已创建”,就把账号升级为付费版,那么用户侧就会看到一种错觉:好像只要填一组看起来合法的信息,就能拿到付费权益。

严格来说,这不是“IBAN 本身万能”,而是系统把“支付流程中的中间状态”误当成了“最终到账状态”。

本地模拟:一个容易出问题的订阅流程

假设我们有一个 SaaS 产品,用户要升级到 Pro。错误设计可能是这样的:

用户选择套餐
-> 前端选择国家和付款方式
-> 服务端创建订阅
-> 支付服务商返回 checkout session created
-> 服务端立即把用户改成 Pro
-> 后续再等支付结果

这个流程最大的问题在第四步到第五步。

checkout session created 只代表“结账会话创建了”,不代表钱已经到账。对于某些异步支付方式,它更不代表最终成功。

错误伪代码大概长这样:

func HandleCheckoutCreated(userID string, plan string) {
    // 错误:创建结账会话不等于支付成功
    UpdateUserPlan(userID, plan)
}

这样一来,只要用户能让系统走到“结账会话创建成功”,就可能短暂拿到付费权益。

正确做法:支付状态机要分层

更稳妥的设计应该把订阅状态拆开:

free
pending_payment
active
past_due
canceled
blocked

用户提交付款资料后,最多进入 pending_payment,不能直接进入 active

只有支付服务商通过可信回调告诉你“支付成功”,并且服务端校验金额、币种、订单、用户、套餐都一致后,才能发放权益。

更合理的伪代码是:

func HandleCheckoutCreated(userID string, plan string) {
    CreateSubscription(userID, plan, "pending_payment")
}

func HandlePaymentSucceeded(event PaymentEvent) error {
    order := FindOrder(event.OrderID)
    if order.UserID != event.UserID {
        return errors.New("user mismatch")
    }
    if order.Amount != event.Amount || order.Currency != event.Currency {
        return errors.New("amount mismatch")
    }
    if !VerifyProviderSignature(event) {
        return errors.New("invalid signature")
    }
    ActivateSubscription(order.UserID, order.Plan)
    return nil
}

func HandlePaymentFailed(event PaymentEvent) {
    MarkSubscriptionPastDue(event.UserID)
}

注意这里有几个关键点:

  • 权益发放只发生在可信支付成功事件之后
  • 支付事件必须验签
  • 金额、币种、订单号、用户 ID、套餐必须逐项核对
  • 失败、拒付、撤销要能把权益收回或冻结

前端为什么不是防线

很多“0 元购”文章会提到地区、地址、付款方式、前端结账页选择项。开发者容易误判为“只要前端不显示某个支付方式就安全了”。

这不够。

前端运行在用户浏览器里,用户可以:

  • 修改请求参数
  • 重放接口
  • 使用代理观察流量
  • 篡改前端状态
  • 调用隐藏接口
  • 使用脚本自动化提交

所以前端可以做体验控制,但不能做最终信任边界。

服务端必须重新判断:

  • 该国家或地区是否允许这个支付方式
  • 用户是否有资格使用这个价格
  • 套餐和价格是否来自服务端价格表
  • 优惠和折扣是否真实有效
  • 付款资料是否来自支付服务商的可信 token
  • 支付结果是否已经最终成功

Figma 免费版其实能覆盖什么

如果只是想正常用 Figma,不一定要上来就买付费版。按照 Figma 官方帮助文档,Figma 有 Starter、Professional、Organization、Enterprise 四类主套餐;Figma for Education 还为符合条件的学生和教育工作者提供免费访问。

普通个人使用,Starter 通常够做这些事:

  • 学习 Figma 基础操作
  • 做少量个人设计稿
  • 查看和评论文件
  • 轻量协作
  • 尝试 FigJam、Slides、Design 等基础工作流

真正需要付费的场景,一般是:

  • 团队项目和文件数量变多
  • 需要更完整的版本、权限和协作管理
  • 需要组织级设计系统
  • 需要集中管理插件、组件库、成员和工作区
  • 企业需要审计、安全、SSO、合规和更强的治理能力

所以与其冒账号和法律风险去找所谓“0 元购”,不如先判断自己到底卡在哪个限制上。

合法省钱思路

更稳妥的方式有几种:

  1. 个人学习先用 Starter。
  2. 学生和教师看是否符合 Figma for Education 条件。
  3. 团队先从少量付费席位开始,不要全员一刀切升级。
  4. 定期清理不用的编辑者席位。
  5. 把只需要查看、评论的人设为合适的非编辑权限。
  6. 年付前先用月付验证团队是否真的需要。
  7. 对企业需求,直接走官方销售和合规采购。

这些方式不刺激,但可持续,也不会把账号、项目文件和团队数据置于风险里。

SaaS 支付系统防护清单

如果你在做 SaaS 订阅系统,可以按下面这份清单自查。

订单与价格:

  • 价格、币种、税费、折扣只由服务端计算
  • 前端提交的 plan、price、country 只能作为候选输入
  • 服务端保存订单快照,后续回调按快照核对

支付状态:

  • checkout_created 不发放正式权益
  • 异步支付先进入 pending_payment
  • 只有 payment_succeeded 或等价的最终成功事件才激活
  • payment_faileddisputerefundchargeback 要能降级或冻结

回调安全:

  • 所有支付回调必须验签
  • 回调必须幂等
  • 金额、币种、订单、用户、套餐逐项校验
  • 失败事件不能被静默忽略

风控:

  • 新账号高价值套餐延迟发放或限制高风险功能
  • 异常地区、代理、设备、付款方式组合进入审核
  • 同一支付资料、IP、设备、邮箱域名异常聚合要告警
  • 免费试用、优惠券、异步支付方式要有单独限额

日志和审计:

  • 记录 checkout session、payment intent、subscription、user、provider event 的关联
  • 敏感字段脱敏
  • 保留权益发放和收回日志
  • 能快速回答“这个用户为什么被升级”

一句话总结

所谓 Figma 0 元购这类传闻,真正暴露的是订阅系统的信任边界问题:不能把“用户提交了付款资料”当成“支付已经成功”。对 SaaS 来说,防护重点不是藏前端按钮,而是把价格、订单、支付状态、权益发放全部收回服务端,并以支付服务商的可信成功事件作为唯一发放依据。

参考资料