数据库:别让所有人都能读写
**把密钥藏好,和把数据锁好,是两件独立的事。**只做第一件,数据照样能被人整个拖走。
先看一个真实的
Section titled “先看一个真实的”Moltbook,2026 年 1 月 28 日上线。创始人公开说自己「没写一行代码」。
三天后,安全公司 Wiz 的研究员发现它的生产数据库整个是敞开的:
- 150 万个 API token
- 35,000 个邮箱地址
- agent 之间的私信
根因两条,缺一不可:
- AI 生成的代码把 Supabase 的 key 放进了客户端 JS(这是 L6·密钥 那一节的问题)
- 没开 RLS(行级安全)
SupaExplorer 扫了 5 个独立产品目录站上的 20,052 个已上线 URL(HN 讨论,53 分):
- 2,217 个域名存在暴露
- 暴露率 11.04%
- 2,325 处严重暴露
Supabase 的 CEO 本人在帖子下面回应了,说已经上线了 GitHub 密钥自动吊销、RLS 强制工具、安全 lint,还说「合同要求 vibe coding 平台接入我们的 Security Advisors」。
厂商要靠合同去逼平台接安全检查——这说明这个问题有多普遍。
另一组数据:Georgia Tech 的 Vibe Security Radar,2026 年 3 月单月追踪到 35 条由 AI 生成代码直接导致的 CVE,而 1 月只有 6 条。
什么是 RLS
Section titled “什么是 RLS”RLS = Row Level Security,行级安全。
普通的权限是「这张表你能不能看」。RLS 是「这张表里哪几行你能看」。
举个例子。你做了个记账应用,bills 表里有所有用户的账单:
| id | user_id | 金额 | 备注 |
|---|---|---|---|
| 1 | 张三 | 200 | 吃饭 |
| 2 | 李四 | 5000 | 房租 |
没有 RLS:张三登录后,只要会发一个请求,能把李四的账单一起读出来。前端只显示他自己的,不代表后端只给了他自己的——F12 里什么都看得见。
有 RLS:数据库层面规定「只能读 user_id 等于你自己的行」。张三怎么发请求,都只拿得到第 1 行。
跟 AI 提需求时怎么说
Section titled “跟 AI 提需求时怎么说”默认情况下 AI 会给你「能跑」的版本——通常就是数据库全开。把这段加进你的需求:
数据库必须开启行级安全(RLS),默认拒绝所有访问,再逐张表写明确的读写策略。每张表告诉我:谁能读、谁能写、依据哪个字段判断。前端只允许拿到当前登录用户自己的数据。
然后让它把策略列给你看,一张表一条,你自己过一遍。看不懂就问它「这条策略允许谁读什么」,直到你能用大白话复述出来。
查法一:用无痕窗口当陌生人
Section titled “查法一:用无痕窗口当陌生人”打开无痕窗口(不登录),访问你的站,然后:
- 按
F12→ Network - 正常翻一遍页面
- 看每个请求的 Response
任何一条返回了「本来该登录才能看」的数据 = 数据库没锁好。
查法二:直接问数据库
Section titled “查法二:直接问数据库”如果你用 Supabase 这类服务,后台一般有安全检查页(Security Advisor / Linter)。打开它,把红色的项目全看一遍。
「表未启用 RLS」这类警告,一条都不能留。
查法三:把 anon key 当公开信息来测
Section titled “查法三:把 anon key 当公开信息来测”前端用的那个 anon / public key 本来就是公开的,不是密钥。拿它直接对数据库发一个查询:
curl "https://<你的项目>.supabase.co/rest/v1/<表名>?select=*" \ -H "apikey: <你的 anon key>"如果这条命令返回了数据,那全世界都能拿到这些数据。
学完这一节,你应该能做到
Section titled “学完这一节,你应该能做到”- 说得清「藏密钥」和「锁数据库」为什么是两件事
- 用大白话解释什么是 RLS,以及它跟「前端只显示自己的数据」区别在哪
- 提需求时会明确要求「默认拒绝 + 逐表策略」,并让 AI 把策略列出来给你看
- 用无痕窗口自己查一遍,拿不到不该给的数据
- 用 anon key 直接查库,返回空或报错,不返回全表