跳到正文

在浏览器里发现了 Supabase 的密钥?第一个小时该做什么

前端中的 service role 密钥或 secret 密钥,会让任何人完全掌控你的数据库。正确的顺序是:作废、替换、查看日志,再修复根源。

阅读约 5 分钟

你按照我们的 10 分钟 Supabase 自查,在应用的 JavaScript 中搜索 service_role 或 sb_secret_,结果找到了。也可能是有人发邮件告诉你,他发现了这个密钥。无论哪种情况,能够绕过数据库所有安全规则的密钥已经公开了。

这是用 AI 开发的应用上线时可能犯下的最严重的错误,也是最常见的错误之一。好消息是:只要按正确的顺序处理,大约一个小时就能修复。

这个密钥为什么特殊

Supabase 为每个项目提供两类密钥:

密钥 应该放在哪里 能做什么
publishable 密钥(sb_publishable_…)或旧版 anon 密钥 浏览器 只能执行 Row Level Security 规则允许的操作
secret 密钥(sb_secret_…)或旧版 service_role 密钥 仅限服务器 一切操作:完全绕过 Row Level Security

拿到 secret 密钥的陌生人,根本不需要寻找规则中的漏洞。他可以读取所有表、修改任何一行、删除数据,还能从私有存储中下载文件。你的规则对他完全不起作用。

第 0–10 分钟:确认泄露的是哪个密钥

在 Supabase 控制台中打开 Project Settings → API Keys,与你在浏览器中找到的内容进行比对:

  • 如果以 sb_secret_ 开头,就是新版 secret 密钥。可以单独替换它,不影响其他任何东西。
  • 如果是以 eyJ 开头的长令牌,就是旧版 service_role 密钥。旧版密钥不能逐个轮换,处理方法不同(见下文)。

同时记下这个密钥在哪里被使用:哪个文件、哪个功能。AI 工具之所以把它放进前端,通常是因为某个操作用公开密钥失败了,原因多半是缺少 RLS 规则,于是用绕过 RLS 的密钥走了捷径。

第 10–30 分钟:替换密钥

如果是新版 secret 密钥(sb_secret_)

  1. 在 API Keys 中创建一个新的 secret 密钥,并用能说明用途的名称命名(例如 edge-functions)。
  2. 把新密钥配置到服务器代码需要它的所有地方:Edge Functions 的 secrets、托管平台的环境变量、后台任务等。
  3. 删除泄露的密钥。使用它的请求会立即失败。

如果是旧版 service_role 密钥

  1. 如果还没有,在 API Keys 页面创建一个 publishable 密钥和一个 secret 密钥。
  2. 把前端的 anon 密钥换成 publishable 密钥,把服务器代码中的 service_role 换成 secret 密钥,然后部署。
  3. 在同一页面停用旧版 API 密钥。这会同时停用 anon 和 service_role 两个密钥,所以必须先完成第 2 步。如果遗漏了某个客户端,Supabase 允许重新启用,因此这一步是可以撤销的。

Supabase 本来就在逐步淘汰旧版密钥,所以这项工作迟早都要做。

第 30–45 分钟:彻底把密钥移出前端

替换密钥可以止住泄露,但依赖它的代码现在会出错。不要为了修复而把新的 secret 密钥再放回浏览器,而是把这部分工作移到服务器上:

  • 使用 Supabase Edge Function 处理需要高权限的操作(发送邀请、写入管理表、调用付费 API)。Edge Functions 可以从运行环境中读取项目的 secret 密钥,无需粘贴到代码里。
  • 或者编写一条 RLS 规则,只允许该页面真正需要的操作。AI 之所以动用 secret 密钥,往往是因为某张表开启了 RLS,却没有为登录用户设置任何规则。有了正确的规则,就不再需要 secret 密钥。

然后,在构建后的 JavaScript 中再次搜索 sb_secret_、service_role 以及新密钥的前几个字符。目标是零匹配。

第 45–60 分钟:查明密钥暴露期间发生了什么

你需要知道是否有人用过这个密钥,而这需要趁日志还在的时候查看。

  • 在控制台的 Logs 中查看暴露期间的 API 请求:异常的请求量、对应用从不读取的表的请求、使用 select=* 的批量下载、不是你执行的删除操作。
  • 在 Auth → Users 中检查是否有你不认识的账户,在存储中检查是否有你没有上传过的文件。
  • 如果怀疑数据被改动,在做任何其他更改之前,先确认你的套餐包含哪些备份或时间点恢复功能。

Supabase 的日志保留时间取决于套餐,可能很短。请今天就处理,不要拖到下周。

防止再次发生

AI 工具会重复它在你的项目中见过的做法。几个习惯可以防止第二次泄露:

  • secret 密钥只放在服务器端的环境变量中,绝不放进框架会发送到浏览器的变量里(在 Vite 中,所有以 VITE_ 开头的变量都会进入打包文件;在 Next.js 中则是以 NEXT_PUBLIC_ 开头的变量)。
  • 每个服务使用一个独立命名的 secret 密钥,这样一旦泄露,只需替换一个。
  • 每次发布前,在构建结果中搜索 sb_secret_ 和 service_role,只需几秒钟。
  • 当 AI 建议用 secret 密钥来消除某个错误时,要把它当作缺少 RLS 规则的信号。

如果你希望有人检查整个应用,包括密钥、规则、存储和身份验证,我们免费的 Security Check 会以只读方式从外部进行检查,并告诉你应该优先修复什么。

SupabaseAPI 密钥AI 开发的应用

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

全部文章