了解 API 密钥
Supabase 允许您对哪些应用程序组件可以访问您的项目进行细粒度控制,通过 API 密钥实现。
API 密钥提供数据访问的第一层身份验证。Auth 在此基础上构建。下表涵盖了差异
| 责任 | 问题 | 答案 |
|---|---|---|
| API 密钥 | 谁在访问项目? | 网页、移动应用、服务器、边缘函数… |
| Supabase Auth | 什么在访问项目? | Monica, Jian Yang, Gavin, Dinesh, Laurie, Fiona… |
概述#
API 密钥验证一个应用程序组件,使其能够访问 Supabase 服务。应用程序组件可能是一个网页、一个移动应用或一个服务器。API 密钥不区分用户,仅区分应用程序。
可以使用 Supabase 的 API 密钥类型有 4 种
| 类型 | 格式 | 权限 | 可用性 | 用途 |
|---|---|---|---|---|
| 公开密钥 | sb_publishable_… | 低 | 平台 | 安全地在线暴露:网页、移动或桌面应用、GitHub Actions、CLI、源代码。 |
| 私有密钥 | sb_secret_… | 较高 | 平台 | 仅在应用程序的后端组件中使用:服务器、已保护的 API(管理面板)、边缘函数、微服务等。它们提供对项目数据的完全访问权限,绕过 行级安全。 |
anon | JWT(长期有效) | 低 | 平台、CLI | 与公开密钥完全相同。 |
service_role | JWT(长期有效) | 较高 | 平台、CLI | 与私有密钥完全相同。 |
anon 和 service_role 密钥基于项目的 JWT 密钥。它们在项目创建时生成,并且只能在轮换 JWT 密钥时更改。这可能会在生产应用程序中导致重大问题。请改用公开密钥和私有密钥。
API 密钥的更改
Supabase 正在更改密钥的工作方式,以提高项目安全性和开发人员体验。您可以 阅读完整的公告,但在过渡期间,您可以使用当前的 anon 和 service_role 密钥以及新的可发布密钥,格式为 sb_publishable_xxx,它将取代旧的密钥。
查找密钥的位置#
您可以在几个不同的位置找到 API 密钥。
在大多数情况下,您可以从 项目的 Connect 对话框获取正确的密钥,但如果您想要特定的密钥,则可以在 项目的设置页面中的 API 密钥部分找到所有密钥
- 对于旧版密钥,从 旧版 API 密钥 选项卡中复制
anon密钥用于客户端操作,并复制service_role密钥用于服务器端操作。 - 对于新密钥,打开 API 密钥 选项卡,如果您还没有可发布密钥,请单击 创建新的 API 密钥,并复制 可发布密钥 部分中的值。
anon 和公开密钥#
anon 和公开密钥保护应用程序的公共组件。公共组件运行在无法保护任何密钥的环境中。这些包括
- 网页,其中密钥捆绑在源代码中。
- 移动或桌面应用程序,其中密钥捆绑在编译后的包或可执行文件中。
- CLI、脚本、工具或其他预构建的可执行文件。
- 其他公开可用的 API,在没有先前的额外授权的情况下返回密钥。
这些环境始终被认为是公开的,因为任何人都可以从源代码或构建工件中检索密钥。混淆可以增加难度,但永远无法消除可能性。(通常,混淆、图灵测试挑战和专业知识不被视为保护密钥目的的授权。)
与 Supabase Auth 的交互#
使用 anon 或公开密钥并不意味着您的用户是匿名的。(将这两个密钥都视为公开密钥,而不是 anon,可以使思维模型更清晰。)
您的应用程序可以使用公开密钥进行身份验证,而您的用户可以使用他们的个人 JWT 通过 Supabase Auth 进行身份验证
| 密钥 | 用户通过 Supabase Auth 登录 | 用于 RLS 等的 Postgres 角色 |
|---|---|---|
| 可发布密钥 | 否 | anon |
anon | 否 | anon |
| 可发布密钥 | 是 | 已认证 |
anon | 是 | 已认证 |
保护#
这些密钥为项目的的数据、性能和账单提供第一层保护,例如
- 提供基本的拒绝服务保护,需要最低限度的知识。
- 通过忽略机器人、爬虫、自动化漏洞扫描器和其他善意或随机的互联网活动来保护您的账单。
安全注意事项#
由于可以始终从公共组件检索密钥,因此公开密钥和 anon 密钥无意保护以下内容
- 静态或动态代码分析和逆向工程尝试。
- 使用浏览器中的网络检查器。
- 跨站点请求伪造、跨站点脚本、网络钓鱼攻击。
- 中间人攻击。
在使用公开密钥或 anon 密钥时,对项目数据的访问受到内置 anon 和 authenticated 角色的 Postgres 的保护。为了获得完全保护,请确保
- 您已在所有表上启用行级安全。
- 您定期检查行级安全策略,以了解授予
anon和authenticated角色的权限。 - 您在不了解所做更改的情况下,不要修改角色的属性。
项目的 安全顾问 会不断检查内置 Postgres 角色中常见的安全问题。请务必仔细审查每个发现后再将其驳回。
service_role 和私有密钥#
与 anon 和公开密钥不同,service_role 和私有密钥允许对项目数据进行更高的访问权限。它仅用于应用程序的安全、开发人员控制的组件中,例如
- 服务器,它们自己实现先前的授权,例如边缘函数、微服务、传统或专门的 Web 服务器。
- 定期作业、队列处理器、主题订阅者。
- 管理和后台工具,仅具有先前的授权检查。
- 数据处理管道,例如用于分析、报告、备份或数据库同步。
切勿公开暴露您的 service_role 和私有密钥。您的数据有风险。不要:
- 添加到网页、公共文档、源代码、捆绑到移动、桌面或 CLI 应用程序的可执行文件中。
- 通过聊天应用程序、电子邮件或短信发送给您的同事。
- 即使在
localhost上,也不要在浏览器中使用! - 不要通过 URL 或查询参数传递,因为这些通常会被记录。
- 在没有先前的日志清理的情况下,小心地将它们传递在请求标头中。
- 即使是潜在的无效 API 密钥,也要格外小心地记录。简单的错误可能会在将来泄露真实的密钥。
- 在没有完全磁盘加密且您不直接拥有或控制的硬件设备上(例如公共计算机、朋友的笔记本电脑等)上泄露、复制、使用或操作。
确保您使用 安全编码实践 小心处理它们。
私有密钥和 service_role 基于 JWT 的 API 密钥通过内置 service_role Postgres 角色授权访问您的项目数据。通过设计,此角色具有对项目数据的完全访问权限。它还使用 BYPASSRLS 属性,跳过您附加的任何和所有行级安全策略。
私有密钥是对旧的基于 JWT 的 service_role 密钥的改进,我们建议尽可能使用它。它增加了更多的检查以防止滥用,特别是
- 您无法在浏览器中使用私有密钥(匹配
User-Agent标头),并且它将始终回复 HTTP 401 Unauthorized。 - 如果您不使用它们,则不需要任何私有密钥。
处理私有密钥的最佳实践#
以下是一些关于如何安全地使用私有密钥的入门指南
- 始终在您完全拥有或控制的计算机上使用私有密钥。
- 使用安全且加密的发送工具与他人共享 API 密钥(通常由好的密码管理器提供),但最好使用 API 密钥 仪表板。
- 最好在文件中或环境变量中加密它们。
- 不要添加到源代码控制中,尤其是在 CI 脚本和工具中。最好使用工具的本机密钥功能。
- 最好为应用程序的每个单独的后端组件使用单独的私有密钥,这样,如果发现其中一个存在漏洞或泄露密钥,您只需要更改它,而无需全部更改。
- 即使私有密钥在使用浏览器时始终返回 HTTP 401 Unauthorized 错误,但这并不意味着攻击者不会使用其他工具。立即删除!
- 如果您必须将它们包含在日志中,请记录前几个随机字符(但不要超过 6 个)。
- 如果您希望记录或存储使用了哪个有效的 API 密钥,请将其存储为 SHA256 哈希值。
如果私有密钥或 service_role 泄露或受到损害该怎么办?#
如果发生这种情况,或者您怀疑发生了这种情况,请不要着急。确保您已充分考虑情况并首先修复了怀疑或漏洞的根本原因。考虑使用 OWASP 风险评级方法 作为识别事件严重程度并计划下一步行动的简便方法。
轮换私有密钥(sb_secret_...)很容易且无痛。使用 API 密钥 仪表板创建一个新的私有 API 密钥,然后用泄露的密钥替换它。一旦所有组件都使用新的密钥,请删除泄露的密钥。
删除私有密钥是不可逆的,一旦完成,它将永远消失。
如果您仍在使用的基于 JWT 的 service_role 密钥,则有两个选项。
- 强烈建议: 将
service_role密钥替换为新的私有密钥。按照上述指南,就像您正在轮换现有的私有密钥一样。 - 轮换项目的 JWT 密钥。 仅当您怀疑 JWT 密钥本身已泄露时才建议执行此操作。考虑将基于 JWT 的
anon密钥切换为公开密钥,并将所有基于 JWT 的service_role密钥切换为私有密钥。然后轮换 JWT 密钥。如果您在移动、桌面或 CLI 应用程序中使用基于 JWT 的密钥,请查看常见问题解答!
已知限制和兼容性差异#
由于公开密钥和私有密钥不再基于 JWT,因此存在一些已知的限制和兼容性差异,您可能需要为此做好计划
- 您无法在
Authorization: Bearer ...标头中发送公开密钥或私有密钥,除非该值完全等于apikey标头。在这种情况下,您的请求将被转发到项目的数据库,但将被拒绝,因为该值不是 JWT。 - 边缘函数仅支持 JWT 验证 通过
anon和service_role基于 JWT 的 API 密钥。您需要使用--no-verify-jwt选项才能使用公开密钥和私有密钥。在这种方式下,Supabase 平台不会验证apikey标头。在边缘函数代码本身内实现您自己的apikey标头授权逻辑。 - 公共实时连接的持续时间限制为 24 小时,除非通过 Supabase Auth 或受支持的第三方 Auth 提供商进行升级和进一步维护,才能延长连接时间。
常见问题解答#
我正在移动应用、桌面应用或 CLI 应用中使用基于 JWT 的 anon 密钥,并且需要轮换我的 service_role JWT 密钥?#
如果您知道或怀疑 JWT 密钥本身已泄露,请参阅关于 轮换 JWT 的部分。
如果 JWT 密钥是安全的,建议用您可以在 API 密钥 仪表板中创建的新密钥替换基于 JWT 的 service_role 密钥。这将防止您的应用程序停机。
在启用发布密钥和私有密钥后,我仍然可以使用我旧的 anon 和 service-role API 密钥吗?#
是的。这允许您在两组密钥都处于活动状态时逐步切换您的客户端,从而实现零停机时间的 API 密钥转换。有关在所有客户端切换完成后如何停用您的密钥,请参阅下一个问题。
在切换到发布密钥和私有密钥后,如何停用基于 JWT 的 anon 和 service_role API 密钥?#
您可以在 API 密钥 仪表板中执行此操作。为了防止应用程序组件停机,请使用页面上的最后使用指示器确认这些密钥不再使用后再停用它们。
如有需要,您可以重新激活它们。
为什么不再推荐基于 JWT 的 anon 和 service_role 密钥?#
自 Supabase 成立以来,基于 JWT 的 anon 和 service_role 密钥对于您的项目来说,在简单性和相对安全性之间做出了正确的权衡。不幸的是,它们在实际应用中带来了一些真正的挑战,尤其是在轮换和安全最佳实践方面。
更喜欢发布密钥和私有密钥 (sb_publishable_... 和 sb_secret_...) 的主要原因包括
- JWT 密钥(如果您自己铸造 JWT)与
anon(低权限)、service_role(高权限)和authenticated(由 Supabase Auth 发行)Postgres 角色之间的紧密耦合。 - 在不造成停机的情况下,无法独立轮换密钥的各个方面。
- 无法回滚不必要或存在问题的 JWT 密钥轮换。
- 发布移动应用程序的新版本可能需要几天,并且经常在 Apple 的 App Store 和 Google 的 Play Store 的应用审核阶段需要数周时间。强制轮换可能导致移动应用用户数周的停机时间。
- 用户可能会继续使用版本非常旧的桌面、CLI 和移动应用,这使得在没有强制版本升级的情况下无法进行轮换。
- JWT 的有效期为 10 年,这为恶意行为者提供了更多可利用的机会。
- JWT 是自引用且包含大量冗余信息,这些信息对于实现其主要目的并不必要。
- JWT 很大,难以解析、验证和操作——导致不安全的日志记录或糟糕的安全实践。
- 它们是用对称 JWT 密钥签名的。
为什么 CLI / 自托管中没有发布密钥或私有密钥?#
发布密钥和私有密钥仅在 Supabase 托管平台上可用。它们由我们的 API 网关组件管理,该组件目前没有 CLI 等效项。
我们正在研究在未来提供类似但范围有限的支持,用于发布密钥或私有密钥。目前,您只能在那里使用基于 JWT 的 anon 和 service_role 密钥。
对于高级用户,请参阅以下问题,了解这些密钥在托管平台上是如何实现的,以便了解如何为自己提供类似的功能。
在托管平台上如何实现发布密钥和私有密钥?#
当您的应用程序使用 Supabase API 时,它们会通过 Supabase 托管平台上的 API 网关组件。这为我们(以及因此为您)提供了以下功能:
- 可观察性和日志记录。
- 性能和请求路由(例如到只读副本)。
- 安全性,用于阻止全局范围内的恶意模式或行为。
此 API 网关组件能够验证 API 密钥(在 apikey 请求标头中发送,或对于 WebSocket 在查询参数中发送)与您项目的发布密钥和私有密钥列表。如果找到匹配项,它会铸造一个临时、短期的 JWT,然后将其转发到您项目的服务器。
如果您使用 Kong、Envoy、NGINX 或类似的可编程代理,则可能可以复制类似的行为。