名称:supabase-extract-anon-key 描述:从客户端代码中提取Supabase匿名/公共API密钥。此密钥在客户端应用中预期存在,但对于RLS测试很重要。
Supabase 匿名密钥提取
🔴 关键:需要渐进式文件更新
您必须随着进行写入上下文文件,而不是仅在结束时。
- 在每次发现后立即写入
.sb-pentest-context.json- 在每次操作前后记录到
.sb-pentest-audit.log- 不要等到技能完成才更新文件
- 如果技能崩溃或中断,所有之前的发现必须已经保存
这不是可选的。未能渐进式写入是关键错误。
此技能从客户端代码中提取Supabase匿名(公共)API密钥。
何时使用此技能
- 提取Supabase URL后,获取API密钥进行测试
- 验证是否只有匿名密钥(非服务密钥)暴露
- 在运行需要身份验证的API审计技能之前
先决条件
- Supabase URL已提取(或自动调用
supabase-extract-url) - 目标应用可访问
理解匿名密钥
匿名密钥(也称为公共密钥)是:
- ✅ 预期在客户端代码中
- ✅ 安全当RLS(行级安全)正确配置时
- ⚠️ 风险如果RLS缺失或配置错误
- ❌ 不同于 service_role密钥(应永远不在客户端代码中)
密钥格式
Supabase匿名密钥是JWT:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImFiYzEyMyIsInJvbGUiOiJhbm9uIiwiaWF0IjoxNjQwMDAwMDAwLCJleHAiOjE5NTUzNjAwMDB9.xxxx
密钥特征:
- 以
eyJ开头(base64编码的{"alg":) - 包含
"role":"anon"在有效负载中 - 项目引用在
"ref"声明中
提取模式
技能搜索:
1. 直接密钥赋值
const SUPABASE_KEY = 'eyJhbGci...'
const SUPABASE_ANON_KEY = 'eyJhbGci...'
2. 客户端初始化
createClient(url, 'eyJhbGci...')
createClient(url, process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY)
3. 环境变量模式
NEXT_PUBLIC_SUPABASE_ANON_KEY
VITE_SUPABASE_ANON_KEY
REACT_APP_SUPABASE_KEY
SUPABASE_KEY
使用
基本提取
从 https://myapp.example.com 提取Supabase匿名密钥
如果URL已知
为项目 abc123def 提取匿名密钥
输出格式
═══════════════════════════════════════════════════════════
匿名密钥已提取
═══════════════════════════════════════════════════════════
密钥类型:匿名(公共)
严重性:ℹ️ 预期(验证RLS配置)
密钥:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJz
dXBhYmFzZSIsInJlZiI6ImFiYzEyM2RlZiIsInJvbGUiOiJhbm
9uIiwiaWF0IjoxNjQwMDAwMDAwLCJleHAiOjE5NTUzNjAwMDB9
.xxxxxxxxxxxxx
解码有效负载:
├── iss:supabase
├── ref:abc123def
├── role:anon
├── iat:2021-12-20T00:00:00Z
└── exp:2031-12-20T00:00:00Z
找到位置:
└── /static/js/main.js(第1253行)
createClient('https://abc123def.supabase.co', 'eyJhbGci...')
下一步:
├── 运行 supabase-audit-rls 测试RLS是否保护您的数据
├── 运行 supabase-audit-tables-read 查看可访问内容
└── 运行 supabase-extract-service-key 检查关键泄漏
上下文已更新:.sb-pentest-context.json
═══════════════════════════════════════════════════════════
密钥验证
技能验证提取的密钥:
验证:
├── 格式:✅ 有效JWT结构
├── 解码:✅ 有效负载可读
├── 角色:✅ 确认为“匿名”角色
├── 项目:✅ 匹配提取的URL(abc123def)
└── 过期:✅ 未过期(过期于2031-12-20)
多个密钥
如果找到多个密钥:
═══════════════════════════════════════════════════════════
找到多个密钥
═══════════════════════════════════════════════════════════
⚠️ 检测到2个潜在Supabase密钥
1. 匿名密钥(已确认)
└── 角色:匿名,项目:abc123def
2. 未知密钥
└── 角色:service_role ⚠️ 参见 supabase-extract-service-key
这可能是一个关键安全问题!
═══════════════════════════════════════════════════════════
上下文输出
保存到.sb-pentest-context.json:
{
"supabase": {
"anon_key": "eyJhbGci...",
"anon_key_decoded": {
"iss": "supabase",
"ref": "abc123def",
"role": "anon",
"iat": 1640000000,
"exp": 1955360000
},
"anon_key_sources": [
{
"file": "/static/js/main.js",
"line": 1253
}
]
}
}
安全评估
| 发现 | 严重性 | 描述 |
|---|---|---|
| 客户端中的匿名密钥 | ℹ️ 信息 | 预期,但测试RLS |
| 匿名密钥过期 | ⚠️ P2 | 应轮换密钥 |
| 多个匿名密钥 | ⚠️ P2 | 可能表示密钥轮换问题 |
| 角色不是“匿名” | 🔴 P0 | 错误密钥类型暴露! |
常见问题
❌ 问题: 找到密钥但无法解码 ✅ 解决方案: 可能被混淆或拆分。尝试:
从 https://myapp.example.com 提取带去混淆的匿名密钥
❌ 问题: 密钥与URL项目不匹配 ✅ 解决方案: 应用可能使用多个Supabase项目。记录两个密钥。
❌ 问题: 未找到密钥但检测到Supabase ✅ 解决方案: 密钥可能在运行时获取。检查网络请求:
监控 https://myapp.example.com 的网络以获取匿名密钥
最佳实践提醒
对于阅读此报告的开发者:
- 客户端中的匿名密钥是正常的 — 设计用于此
- RLS是关键 — 匿名密钥依赖于RLS的安全性
- 永远不要在客户端使用service_role — 使用边缘函数替代
- 定期轮换密钥 — 可在Supabase仪表板中使用
强制:渐进式上下文文件更新
⚠️ 此技能必须在执行期间渐进式更新跟踪文件,而不仅仅在结束时。
关键规则:随写随存
不要在结束时批量写入所有内容。而是:
- 开始任何操作前 → 记录操作到
.sb-pentest-audit.log - 每次发现后 → 立即更新
.sb-pentest-context.json - 每次重要步骤后 → 记录完成到
.sb-pentest-audit.log
这确保如果技能中断、崩溃或超时,所有之前的发现都已保存。
必需操作(渐进式)
-
更新
.sb-pentest-context.json与提取数据:{ "supabase": { "anon_key": "eyJhbGci...", "anon_key_decoded": { ... }, "anon_key_sources": [ ... ] } } -
记录到
.sb-pentest-audit.log:[时间戳] [supabase-extract-anon-key] [开始] 开始匿名密钥提取 [时间戳] [supabase-extract-anon-key] [成功] 匿名密钥已提取 [时间戳] [supabase-extract-anon-key] [上下文已更新] .sb-pentest-context.json 已更新 -
如果文件不存在,在写入前创建它们。
未能更新上下文文件是不可接受的。
强制:证据收集
📁 证据目录: .sb-pentest-evidence/02-extraction/
要创建的证据文件
| 文件 | 内容 |
|---|---|
extracted-anon-key.json |
带解码JWT有效负载的匿名密钥 |
证据格式
{
"evidence_id": "EXT-ANON-001",
"timestamp": "2025-01-31T10:07:00Z",
"category": "extraction",
"type": "anon_key",
"severity": "info",
"key_data": {
"key_prefix": "eyJhbGciOiJIUzI1NiI...",
"key_suffix": "...xxxx",
"full_key_length": 256
},
"decoded_payload": {
"iss": "supabase",
"ref": "abc123def",
"role": "anon",
"iat": "2021-12-20T00:00:00Z",
"exp": "2031-12-20T00:00:00Z"
},
"source": {
"file": "/static/js/main.js",
"line": 1253,
"context": "createClient('https://abc123def.supabase.co', 'eyJhbGci...')"
},
"validation": {
"format_valid": true,
"role_confirmed": "anon",
"project_matches": true,
"expired": false
}
}
相关技能
supabase-extract-url— 先获取URL(如果需要自动调用)supabase-extract-service-key— 检查关键服务密钥泄漏supabase-audit-rls— 测试RLS是否保护您的数据supabase-audit-tables-read— 查看使用此密钥可访问的数据