跳到正文

你用 AI 开发的应用在泄露数据吗?10 分钟完成 Supabase 自查

用 Lovable 或 Bolt 基于 Supabase 开发的应用,经常带着任何人都能读取的数据表上线。本文介绍如何在十分钟内自查,以及应该先修复什么。

阅读约 4 分钟

用 Lovable、Bolt 或类似工具开发的应用,通常把数据存放在 Supabase 中。这是个不错的选择:Supabase 是一个真正的 Postgres 数据库,并内置了身份验证。但它有一条 AI 工具并不总会遵守的规则。一旦漏掉,任何人只要打开浏览器的开发者工具,就能读取应用的数据。

本指南介绍如何在大约十分钟内检查你自己的应用,无需安装任何东西。

为什么应用里的密钥是公开的

你的应用在浏览器中与 Supabase 通信,因此浏览器需要一个密钥。这个密钥叫作 anon key(较新的项目中叫 publishable key),会随应用的 JavaScript 一起发布,任何人都能找到它。这是设计使然。

保护数据的不是密钥,而是 Row Level Security(RLS,行级安全):数据库中的规则,决定每个访问者可以读取或修改哪些行。开启 RLS 并配好规则,公开的密钥就无害;关闭 RLS,公开的密钥就能读取整张表。

情况 持有你公开密钥的陌生人能做什么
数据表未开启 RLS 读取(通常还能修改)所有行
开启 RLS,但没有规则 什么也做不了:所有请求都会被拒绝
开启 RLS,规则为 using (true) 对于规则涵盖的操作和角色,等同于未开启 RLS
开启 RLS,规则基于 auth.uid() 只能访问属于当前登录用户的行

第 1 步:列出未开启 RLS 的数据表

在 Supabase 控制台中打开你的项目,进入 SQL Editor,运行:

public schema 中的数据表及其 RLS 状态
select c.relname as table_name,
       c.relrowsecurity as rls_enabled
from pg_class c
join pg_namespace n on n.oid = c.relnamespace
where n.nspname = 'public'
  and c.relkind = 'r'
order by c.relrowsecurity, c.relname;

每一行 rls_enabled = false 都是公开密钥可以访问的数据表。在 Table Editor 中创建的表默认开启 RLS;通过 SQL 创建的表则不会,而大多数 AI 工具正是用 SQL 建表的。

控制台中的 Security Advisor 也会把同样的问题标记为 RLS Disabled in Public。如果它显示了任何错误,先从那里着手。

第 2 步:查找放行一切的规则

开启了 RLS 但规则过于宽松,同样等于敞开大门。列出你的规则:

public schema 中的所有 RLS 策略
select tablename, policyname, cmd, roles, qual, with_check
from pg_policies
where schemaname = 'public'
order by tablename, cmd;

仔细检查 qual 或 with_check 直接为 true 的规则,尤其是针对 anon 或 public 角色的规则。如果 profiles 或 orders 表上有这样的规则,就意味着任何人都能读取所有用户资料或所有订单。

第 3 步:从外部确认

现在像攻击者一样测试:只用公开密钥。在 Project Settings → API 中找到项目 URL 和密钥,然后运行:

用公开密钥读取数据表
curl "https://YOUR-PROJECT.supabase.co/rest/v1/profiles?select=*&limit=5" \
  -H "apikey: YOUR_PUBLIC_KEY"

如何解读结果:

  • 返回了不属于你的数据:这张表已经暴露,请今天就修复。
  • 返回空列表 []:要么表是空的,要么 RLS 把所有数据都过滤掉了,这正是你想要的结果。
  • 返回权限错误:这张表完全无法通过 API 访问,同样没问题。

对每一张存放个人信息、支付数据或其他私密内容的表重复这个测试。

第 4 步:确认应用中没有私密密钥

Supabase 还会提供 service role key(或以 sb_secret_ 开头的 secret key)。它会完全绕过 RLS,只能存放在服务器上。打开你已上线的应用,按 F12,进入 Sources,在 JavaScript 中搜索 service_role 和 sb_secret_。只要出现其中任何一个,就立即在控制台中轮换该密钥,并把需要它的代码移到服务器端函数中。

应该先修复什么

  1. 轮换所有已经暴露到浏览器中的私密密钥。
  2. 为 public schema 中的每张表开启 RLS:alter table public.profiles enable row level security;
  3. 把私密数据表上的 using (true) 规则替换为基于当前登录用户的规则。
  4. 再次执行第 3 步,确认陌生人什么也拿不到。

开启 RLS 后,所有依赖那张开放数据表的页面都会失效。这是预料之中的:每个页面现在都需要一条恰好放行其所需数据的规则。如果你的应用是由 AI 生成的,而你不确定它需要哪些规则,这正是我们的 Security Check 首先要做的工作。

SupabaseLovableRow Level SecurityAI 开发的应用

本文还有以下语言版本: EnglishPortuguêsEspañol日本語

全部文章