跳转到内容

数据库:别让所有人都能读写

**把密钥藏好,和把数据锁好,是两件独立的事。**只做第一件,数据照样能被人整个拖走。

Moltbook,2026 年 1 月 28 日上线。创始人公开说自己「没写一行代码」。

三天后,安全公司 Wiz 的研究员发现它的生产数据库整个是敞开的:

  • 150 万个 API token
  • 35,000 个邮箱地址
  • agent 之间的私信

根因两条,缺一不可:

  1. AI 生成的代码把 Supabase 的 key 放进了客户端 JS(这是 L6·密钥 那一节的问题)
  2. 没开 RLS(行级安全)

SupaExplorer 扫了 5 个独立产品目录站上的 20,052 个已上线 URLHN 讨论,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 = Row Level Security,行级安全

普通的权限是「这张表你能不能看」。RLS 是「这张表里哪几行你能看」。

举个例子。你做了个记账应用,bills 表里有所有用户的账单:

id user_id 金额 备注
1 张三 200 吃饭
2 李四 5000 房租

没有 RLS:张三登录后,只要会发一个请求,能把李四的账单一起读出来。前端只显示他自己的,不代表后端只给了他自己的——F12 里什么都看得见

有 RLS:数据库层面规定「只能读 user_id 等于你自己的行」。张三怎么发请求,都只拿得到第 1 行。

默认情况下 AI 会给你「能跑」的版本——通常就是数据库全开。把这段加进你的需求:

数据库必须开启行级安全(RLS),默认拒绝所有访问,再逐张表写明确的读写策略。每张表告诉我:谁能读、谁能写、依据哪个字段判断。前端只允许拿到当前登录用户自己的数据。

然后让它把策略列给你看,一张表一条,你自己过一遍。看不懂就问它「这条策略允许谁读什么」,直到你能用大白话复述出来。

打开无痕窗口(不登录),访问你的站,然后:

  1. F12 → Network
  2. 正常翻一遍页面
  3. 看每个请求的 Response

任何一条返回了「本来该登录才能看」的数据 = 数据库没锁好。

如果你用 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>"

如果这条命令返回了数据,那全世界都能拿到这些数据。

  • 说得清「藏密钥」和「锁数据库」为什么是两件事
  • 用大白话解释什么是 RLS,以及它跟「前端只显示自己的数据」区别在哪
  • 提需求时会明确要求「默认拒绝 + 逐表策略」,并让 AI 把策略列出来给你看
  • 用无痕窗口自己查一遍,拿不到不该给的数据
  • 用 anon key 直接查库,返回空或报错,不返回全表