关于 supabase-extract-jwt
此安全技能用于查找并分析客户端代码中的 Supabase 相关 JWT。它检查令牌声明和存储引用,帮助识别暴露的密钥、硬编码用户令牌及身份验证信息。
主要功能
- 01查找客户端代码中的 JWT 和 API 密钥
- 02分析令牌声明与过期时间
- 03检测硬编码用户令牌和个人信息
- 04识别 JWT 存储引用
- 05保存发现结果与提取证据
适用场景
- 01检查客户端代码是否暴露 service role 密钥
- 02调查硬编码的用户令牌
- 03审查令牌声明和过期时间
- 04了解身份验证相关代码模式
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ yoanbernabeu/ supabase-pentest-skills --skill supabase-extract-jwt安装后在 Claude Code 中输入/supabase-extract-jwt确认已加载。
详细介绍
Supabase JWT 提取
🔴 严重:必须渐进式更新文件
必须在过程中写入上下文文件,而不是只在最后写入。
- 每次发现后立即写入
.sb-pentest-context.json- 每次操作前后都记录到
.sb-pentest-audit.log- 不要等到技能执行完毕后才更新文件
- 如果技能崩溃或中断,所有先前的发现都必须已经保存
这不是可选项。未能渐进式写入是严重错误。
此技能用于从客户端代码中提取并分析与 Supabase 相关的 JSON Web Token(JWT)。
何时使用此技能
- 查找客户端代码中暴露的所有 JWT 令牌
- 分析令牌声明和过期时间
- 检测硬编码的用户令牌(安全问题)
- 了解身份验证流程
前提条件
- 可以访问目标应用
- 已完成 Supabase 检测(如有需要会自动调用)
Supabase 中的 JWT 类型
| 类型 | 用途 | 客户端暴露情况 |
|---|---|---|
| Anon Key | API 身份验证 | ✅ 预期情况 |
| Service Role Key | 管理员访问 | ❌ 绝不可暴露 |
| Access Token | 用户会话 | ⚠️ 仅动态生成 |
| Refresh Token | 令牌续期 | ⚠️ 仅动态生成 |
检测模式
1. API 密钥(静态)
// Supabase API keys are JWTs
const SUPABASE_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
2. 硬编码的用户令牌(问题)
// ❌ Should never be hardcoded
const userToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiZW1haWwiOiJ1c2VyQGV4YW1wbGUuY29tIn0...'
3. 存储密钥模式
// Code referencing where JWTs are stored
localStorage.getItem('supabase.auth.token')
localStorage.getItem('sb-abc123-auth-token')
sessionStorage.getItem('supabase_session')
用法
基本提取
Extract JWTs from https://myapp.example.com
分析声明
Extract and analyze all JWTs from https://myapp.example.com
输出格式
═══════════════════════════════════════════════════════════
JWT EXTRACTION RESULTS
═══════════════════════════════════════════════════════════
Found: 3 JWTs
─────────────────────────────────────────────────────────
JWT #1: Supabase Anon Key
─────────────────────────────────────────────────────────
Type: API Key (anon)
Status: ✅ Expected in client code
Header:
├── alg: HS256
└── typ: JWT
Payload:
├── iss: supabase
├── ref: abc123def
├── role: anon
├── iat: 2021-12-20T00:00:00Z
└── exp: 2031-12-20T00:00:00Z
Location: /static/js/main.js:1247
─────────────────────────────────────────────────────────
JWT #2: Hardcoded User Token ⚠️
─────────────────────────────────────────────────────────
Type: User Access Token
Status: ⚠️ P1 - Should not be hardcoded
Header:
├── alg: HS256
└── typ: JWT
Payload:
├── sub: 12345678-1234-1234-1234-123456789012
├── email: [email protected]
├── role: authenticated
├── iat: 2025-01-15T10:00:00Z
└── exp: 2025-01-15T11:00:00Z (EXPIRED)
Location: /static/js/debug.js:45
Risk: This token may belong to a real user account.
Even if expired, it reveals user information.
─────────────────────────────────────────────────────────
JWT #3: Storage Reference
─────────────────────────────────────────────────────────
Type: Storage Key Pattern
Status: ℹ️ Informational
Pattern: localStorage.getItem('sb-abc123def-auth-token')
Location: /static/js/auth.js:89
Note: This is the expected storage key for user sessions.
Actual token value is set at runtime.
═══════════════════════════════════════════════════════════
JWT 声明分析
此技能会识别关键声明:
标准声明
| 声明 | 描述 | 安全影响 |
|---|---|---|
sub | 用户 ID | 标识特定用户 |
email | 用户邮箱 | 硬编码时会暴露个人身份信息 |
role | 权限级别 | service_role 属于严重风险 |
exp | 过期时间 | 已过期的令牌风险较低 |
iat | 签发时间 | 表示令牌的创建时间 |
Supabase 特定声明
| 声明 | 描述 |
|---|---|
ref | 项目引用 |
iss | 应为 "supabase" |
aal | 验证器保证级别 |
amr | 使用的身份验证方式 |
安全发现
P0 - 严重
🔴 Service role key exposed (role: service_role)
→ Immediate key rotation required
P1 - 高
🟠 User token hardcoded with PII (email, sub visible)
→ Remove from code, may need to notify user
P2 - 中
🟡 Expired test token in code
→ Clean up, potential information disclosure
上下文输出
保存至 .sb-pentest-context.json:
{
"jwts": {
"found": 3,
"api_keys": [
{
"type": "anon",
"project_ref": "abc123def",
"location": "/static/js/main.js:1247"
}
],
"user_tokens": [
{
"type": "access_token",
"hardcoded": true,
"severity": "P1",
"claims": {
"sub": "12345678-1234-1234-1234-123456789012",
"email": "[email protected]",
"expired": true
},
"location": "/static/js/debug.js:45"
}
],
"storage_patterns": [
{
"pattern": "sb-abc123def-auth-token",
"storage": "localStorage",
"location": "/static/js/auth.js:89"
}
]
}
}
常见问题
❌ 问题: JWT 看起来被截断了
✅ 解决方案: 内容可能跨越多行。此技能会尝试重新拼接。
❌ 问题: 无法解码 JWT
✅ 解决方案: 可能经过加密(JWE)或使用自定义格式。会将其标记为无法解码。
❌ 问题: 误报很多
✅ 解决方案: 一些 Base64 字符串看起来像 JWT。此技能会验证其结构。
硬编码令牌的修复方法
修复前(错误)
// ❌ Never hardcode user tokens
const adminToken = 'eyJhbGciOiJIUzI1NiI...'
fetch('/api/admin', {
headers: { Authorization: `Bearer ${adminToken}` }
})
修复后(正确)
// ✅ Get token from Supabase session
const { data: { session } } = await supabase.auth.getSession()
fetch('/api/admin', {
headers: { Authorization: `Bearer ${session.access_token}` }
})
强制要求:渐进式更新上下文文件
⚠️ 此技能必须在执行过程中渐进式更新跟踪文件,而不是只在最后更新。
关键规则:边操作边写入
不要等到最后才批量写入。应按以下步骤操作:
- 开始任何操作前 → 将操作记录到
.sb-pentest-audit.log - 每次发现后 → 立即更新
.sb-pentest-context.json - 每个重要步骤后 → 将完成情况记录到
.sb-pentest-audit.log
这样可确保即使技能被中断、崩溃或超时,在此之前发现的所有内容都能得到保留。
必需操作(渐进式)
-
更新
.sb-pentest-context.json,加入提取的数据:{ "jwts": { "found": 3, "api_keys": [ ... ], "user_tokens": [ ... ], "storage_patterns": [ ... ] } } -
记录到
.sb-pentest-audit.log:[TIMESTAMP] [supabase-extract-jwt] [START] Beginning JWT extraction [TIMESTAMP] [supabase-extract-jwt] [SUCCESS] Found 3 JWTs [TIMESTAMP] [supabase-extract-jwt] [CONTEXT_UPDATED] .sb-pentest-context.json updated -
如果文件不存在,请在写入前创建文件。
未能更新上下文文件不可接受。
强制要求:证据收集
📁 证据目录: .sb-pentest-evidence/02-extraction/
要创建的证据文件
| 文件 | 内容 |
|---|---|
extracted-jwts.json | 找到的所有 JWT 及其分析结果 |
证据格式
{
"evidence_id": "EXT-JWT-001",
"timestamp": "2025-01-31T10:08:00Z",
"category": "extraction",
"type": "jwt_extraction",
"jwts_found": [
{
"type": "anon_key",
"severity": "info",
"location": "/static/js/main.js:1247",
"decoded_payload": {
"iss": "supabase",
"ref": "abc123def",
"role": "anon"
}
},
{
"type": "hardcoded_user_token",
"severity": "P1",
"location": "/static/js/debug.js:45",
"decoded_payload": {
"sub": "[REDACTED]",
"email": "[REDACTED]@example.com",
"role": "authenticated",
"exp": "2025-01-15T11:00:00Z"
},
"expired": true,
"issue": "Hardcoded user token with PII"
}
],
"storage_patterns_found": [
{
"pattern": "localStorage.getItem('sb-abc123def-auth-token')",
"location": "/static/js/auth.js:89"
}
]
}
相关技能
supabase-extract-anon-key— 专门提取 anon keysupabase-extract-service-key— 检查 service key(至关重要)supabase-audit-auth-config— 分析身份验证配置
评论
支持 Markdown