Creem账户被封后的完整复盘
由于 **Supabase 数据库未开启 RLS(Row-Level Security)策略**,导致用户数据被公开 API 访问并最终被发布到暗网论坛,引发支付平台 Creem 的合规调查。虽然在 **6 小时内完成安全修复并提交完整调查报告**,但由于 **卡组织(Visa/Mastercard)与监管机构介入**,Creem 仍然永久终止商户合作,并冻结余额 **90 天**。这次事件揭示了三个关键问题:Supabase RLS 的默认风险、支付平台合规机制的不可协商性,以及独立开发者对第三方平台的高度依赖。
事件背景
我开发并运营一个 SaaS 产品 。它是一个 AI 换脸工具,主要面向海外用户,通过 API 调用模型生成视频内容并按次收费。
产品技术架构是典型的独立开发者组合:
- 前端:Next.js
- 数据库:Supabase(PostgreSQL)
- 支付:Creem(Merchant of Record)
- AI推理:Replicate
- CDN:Cloudflare R2
产品已经运行了几个月,存在稳定付费用户,每天都会产生订单。虽然整体规模不大,但属于 完全自动化运行的 SaaS,被动收入模型。
Creem平台角色
Creem 是一个 MoR(Merchant of Record)支付平台,核心功能包括:
- 处理全球税务
- 自动生成发票
- 计算不同国家 VAT
- 处理退款
- 承担支付合规责任
对独立开发者来说,这类平台的价值在于 极大降低全球合规门槛。开发者只需要专注产品销售,其余税务和合规工作由平台处理。
事情的转折发生在 2月22日。
数据库配置错误导致的数据泄露
泄露事件发现
我收到一条消息:
在数据泄露论坛 updap.com 上,有人发布了一个帖子:
.net Database Leaked Download
最初我并不相信。因为数据库使用的是 Supabase,理论上支持 RLS 安全策略。
但检查后发现一个严重问题:
数据库 10 张表,大部分没有开启 RLS。
Supabase RLS机制
Supabase 的数据库通过 PostgREST 自动生成 REST API。
这意味着:
- 数据库表会自动暴露为 API
- 如果没有配置 RLS
- API 可以直接读取所有数据
Supabase 官方要求:
如果通过 SQL 创建表,需要手动开启 RLS:
alter table <schema_name>.<table_name> enable row level security;
通过控制台创建的表会默认开启,但 SQL创建的表不会自动启用。
本次泄露的数据类型
泄露的数据包括:
- 用户邮箱
- 用户姓名
- Google OAuth ID
- Creem 客户 ID
- Creem 订阅 ID
- 订阅状态
- 用户积分余额
- 交易记录
- 推荐码
- 邀请关系
唯一没有泄露的是:
信用卡信息
因为所有支付数据都在 Creem 平台,数据库中并没有存储:
- 卡号
- CVV
- 信用卡持有人信息
但从支付平台角度来看,数据库泄露本身已经是严重安全事件。
Creem启动合规调查
Creem很快发送调查通知,并冻结了账户支付能力。
调查要求包括四项内容:
- 列出泄露的数据字段
- 说明调查过程和应对措施
- 是否聘请第三方安全专家
- 完整事件时间线
邮件中明确说明:
- 支付功能立即冻结
- 账户余额同步冻结
并要求 1 个工作日内提交完整报告。
6小时紧急修复
发现问题后,我和 AI 工具一起进行了紧急处理。
整个修复过程分为两部分。
第一步:为所有表补充RLS策略
当天完成了 10 张表的 RLS 修复。
核心策略如下:
| 表名 | 安全策略 |
|---|---|
| billing_customers | 仅允许用户访问自己的记录 |
| billing_subscriptions | 仅允许用户访问自己的记录 |
| credit_balances | 只读自己的数据,写操作仅后端执行 |
| credit_transactions | 只读自己的数据,写操作仅后端执行 |
| billing_events | 完全禁止前端访问 |
| waitlist | 仅允许插入,不允许读取 |
| referral_codes | 仅允许访问自己的记录 |
| video_predictions | 仅允许查看自己的生成任务 |
通过这些策略,数据库 API 访问被完全限制。
第二步:数据库架构迁移
即使补齐 RLS,我仍然决定 彻底迁离 Supabase。
原因很简单:
PostgREST 自动暴露 API + RLS 配置风险 = 长期安全隐患
因此启动了全量迁移。
迁移架构调整
| 模块 | 迁移前 | 迁移后 |
|---|---|---|
| 数据库 | Supabase PostgreSQL | Cloudflare D1 |
| 认证系统 | Supabase Auth | 自建 JWT + HttpOnly Cookie |
| 部署平台 | Vercel | Cloudflare Pages + Workers |
迁移工作量
整个迁移周期 不到两周,主要包括:
- 重建 11 张数据库表结构
- 重写 25 个 API 路由
- 重建认证系统
AI 工具在这次迁移中承担了大量代码生成工作,例如:
- D1 数据库 schema
- API 数据访问层
- 权限控制逻辑
我主要负责:
- 架构设计
- 安全策略
- 测试验证
架构安全性变化
迁移前:
- Supabase 自动生成公开 REST API
- 配置错误可能导致数据库被完全访问
迁移后:
- Cloudflare D1 不提供公开 API
- 所有数据访问必须经过后端
从架构层面避免了类似漏洞。
提交完整调查报告
Creem调查邮件发送后,我提交了一份非常详细的回复。
报告内容包括:
泄露数据清单
逐表列出可能暴露的字段。
未泄露数据
明确说明:
没有任何信用卡数据泄露。
修复措施
包括:
- RLS策略配置
- 数据库迁移计划
- 安全架构调整
时间线
完整记录事件过程:
- 泄露发现
- 漏洞确认
- 安全修复
- 架构迁移
从发现问题到修复完成 只用了几个小时。
最终结果:Creem永久终止合作
Creem最终回复:
- 承认开发者采取了快速修复措施
- 认可调查报告的完整性
但最终决定仍然是:
永久停止提供商户服务
原因是:
卡组织与监管机构已经介入调查。
同时宣布:
- 账户余额冻结 90 天
- 若无拒付或罚款,资金将在冻结期后释放
这意味着:
即使修复完成,支付渠道仍然被终止。
这次事故带来的三个结论
Supabase RLS是高风险配置点
Supabase 本身并不是不安全。
但它的设计特点是:
数据库自动暴露 API
如果开发者忘记配置 RLS:
数据库可能直接被公开访问。
因此必须检查:
- 每一张表是否开启 RLS
- 每一条策略是否正确
如果无法确认这两点,系统就存在潜在风险。
支付平台的合规决定无法谈判
Creem的决定逻辑其实很简单。
一旦 Visa / Mastercard 等卡组织看到数据泄露报告:
支付平台必须优先保护自身合规。
因此他们通常会选择:
直接终止商户合作。
这种情况不仅会发生在 Creem,也可能发生在:
- Stripe
- PayPal
- LemonSqueezy
对支付网络来说:
商户只是风险节点。
最大风险是平台依赖
这次事件让我意识到一个现实:
独立开发者的业务建立在大量第三方平台之上。
例如:
- 数据库平台
- 支付平台
- 部署平台
- 身份认证
- OAuth登录
这些平台都有权在任何时候终止服务。
一旦支付平台终止合作:
收入会立即归零。
后续计划
目前 的基础设施已经完成迁移:
- 数据库:Cloudflare D1
- 认证系统:自建
- 部署平台:Cloudflare Workers
从架构角度来看:
安全性已经明显提高。
接下来要解决的问题是:
重新接入支付渠道。
等 Creem 的 90 天冻结期结束,余额会被释放。
最重要的经验
以前我认为独立开发者最重要的能力是:
快速开发产品。
现在我认为真正关键的能力是:
在任何平台出现问题后,48 小时内恢复业务运行。
不是不用第三方平台。
而是必须确保:
每一个第三方都可以在一周内被替换。
只有这样,产品才不会因为某个平台的决策而彻底停摆。