SupabaseJWT提取Skill supabase-extract-jwt

此技能用于从客户端代码中提取和分析Supabase相关的JSON Web Tokens(JWT),支持安全审计、身份认证流程分析和漏洞检测。关键词包括Supabase、JWT提取、安全审计、网络安全、身份认证。

安全审计 0 次安装 0 次浏览 更新于 3/18/2026

名称: supabase-extract-jwt 描述: 从客户端代码、cookies和本地存储模式中提取和解码Supabase相关的JSON Web Tokens(JWT)。

Supabase JWT 提取

🔴 关键:需要渐进式文件更新

您必须逐步写入上下文文件,而不是仅在最后写入。

  • 每次发现后立即写入 .sb-pentest-context.json
  • 每次操作前后记录到 .sb-pentest-audit.log
  • 不要等到技能完成才更新文件
  • 如果技能崩溃或中断,所有之前的发现必须已经保存

这不是可选的。未能逐步写入是关键错误。

此技能从客户端代码中提取和分析与Supabase相关的JSON Web Tokens(JWT)。

何时使用此技能

  • 查找客户端代码中暴露的所有JWT令牌
  • 分析令牌声明和过期时间
  • 检测硬编码的用户令牌(安全问题)
  • 理解认证流程

先决条件

  • 目标应用程序可访问
  • Supabase检测已完成(如果需要,自动调用)

Supabase中的JWT类型

类型 目的 客户端暴露
匿名密钥 API认证 ✅ 预期
服务角色密钥 管理员访问 ❌ 从不
访问令牌 用户会话 ⚠️ 仅动态
刷新令牌 令牌更新 ⚠️ 仅动态

检测模式

1. API密钥(静态)

// Supabase API密钥是JWT
const SUPABASE_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'

2. 硬编码用户令牌(问题)

// ❌ 永远不应硬编码
const userToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiZW1haWwiOiJ1c2VyQGV4YW1wbGUuY29tIn0...'

3. 存储密钥模式

// 引用JWT存储位置的代码
localStorage.getItem('supabase.auth.token')
localStorage.getItem('sb-abc123-auth-token')
sessionStorage.getItem('supabase_session')

使用

基本提取

从 https://myapp.example.com 提取JWT

带声明分析

从 https://myapp.example.com 提取和分析所有JWT

输出格式

═══════════════════════════════════════════════════════════
 JWT 提取结果
═══════════════════════════════════════════════════════════

 找到: 3 个JWT

 ─────────────────────────────────────────────────────────
 JWT #1: Supabase 匿名密钥
 ─────────────────────────────────────────────────────────
 类型: API密钥(匿名)
 状态: ✅ 预期在客户端代码中

 头部:
 ├── alg: HS256
 └── typ: JWT

 载荷:
 ├── iss: supabase
 ├── ref: abc123def
 ├── role: anon
 ├── iat: 2021-12-20T00:00:00Z
 └── exp: 2031-12-20T00:00:00Z

 位置: /static/js/main.js:1247

 ─────────────────────────────────────────────────────────
 JWT #2: 硬编码用户令牌 ⚠️
 ─────────────────────────────────────────────────────────
 类型: 用户访问令牌
 状态: ⚠️ P1 - 不应硬编码

 头部:
 ├── alg: HS256
 └── typ: JWT

 载荷:
 ├── sub: 12345678-1234-1234-1234-123456789012
 ├── email: developer@company.com
 ├── role: authenticated
 ├── iat: 2025-01-15T10:00:00Z
 └── exp: 2025-01-15T11:00:00Z (已过期)

 位置: /static/js/debug.js:45

 风险: 此令牌可能属于真实用户账户。
       即使已过期,它也泄露用户信息。

 ─────────────────────────────────────────────────────────
 JWT #3: 存储引用
 ─────────────────────────────────────────────────────────
 类型: 存储密钥模式
 状态: ℹ️ 信息性

 模式: localStorage.getItem('sb-abc123def-auth-token')
 位置: /static/js/auth.js:89

 注意: 这是用户会话的预期存储密钥。
       实际令牌值在运行时设置。

═══════════════════════════════════════════════════════════

JWT 声明分析

此技能识别关键声明:

标准声明

声明 描述 安全影响
sub 用户ID 识别特定用户
email 用户邮箱 如果硬编码,暴露PII
role 权限级别 service_role 是关键
exp 过期时间 过期令牌风险较低
iat 签发时间 指示创建时间

Supabase特定声明

声明 描述
ref 项目引用
iss 应为“supabase”
aal 认证保证级别
amr 使用的认证方法

安全发现

P0 - 关键

🔴 服务角色密钥暴露(角色: service_role)
   → 需要立即密钥轮换

P1 - 高

🟠 硬编码用户令牌带有PII(邮箱、sub可见)
   → 从代码中移除,可能需要通知用户

P2 - 中

🟡 代码中过期的测试令牌
   → 清理,潜在信息泄露

上下文输出

保存到 .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": "developer@company.com",
          "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)或自定义格式。标记为不可解码。

问题: 许多误报 ✅ 解决方案: 看起来像JWT的Base64字符串。此技能验证结构。

硬编码令牌的修复

之前(错误)

// ❌ 永远不要硬编码用户令牌
const adminToken = 'eyJhbGciOiJIUzI1NiI...'
fetch('/api/admin', {
  headers: { Authorization: `Bearer ${adminToken}` }
})

之后(正确)

// ✅ 从Supabase会话获取令牌
const { data: { session } } = await supabase.auth.getSession()
fetch('/api/admin', {
  headers: { Authorization: `Bearer ${session.access_token}` }
})

强制:渐进式上下文文件更新

⚠️ 此技能必须在执行期间逐步更新跟踪文件,而不是仅在最后。

关键规则:逐步写入

不要 在最后批量写入所有内容。相反:

  1. 开始任何操作前 → 记录操作到 .sb-pentest-audit.log
  2. 每次发现后 → 立即更新 .sb-pentest-context.json
  3. 每次重要步骤后 → 记录完成到 .sb-pentest-audit.log

这确保如果技能中断、崩溃或超时,所有到该点的发现都已保存。

所需操作(渐进式)

  1. 更新 .sb-pentest-context.json 提取的数据:

    {
      "jwts": {
        "found": 3,
        "api_keys": [ ... ],
        "user_tokens": [ ... ],
        "storage_patterns": [ ... ]
      }
    }
    
  2. 记录到 .sb-pentest-audit.log:

    [时间戳] [supabase-extract-jwt] [开始] 开始JWT提取
    [时间戳] [supabase-extract-jwt] [成功] 找到3个JWT
    [时间戳] [supabase-extract-jwt] [上下文更新] .sb-pentest-context.json 更新
    
  3. 如果文件不存在,在写入前创建。

未能更新上下文文件是不可接受的。

强制:证据收集

📁 证据目录: .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": "硬编码用户令牌带有PII"
    }
  ],

  "storage_patterns_found": [
    {
      "pattern": "localStorage.getItem('sb-abc123def-auth-token')",
      "location": "/static/js/auth.js:89"
    }
  ]
}

相关技能

  • supabase-extract-anon-key — 专门提取匿名密钥
  • supabase-extract-service-key — 检查服务密钥(关键)
  • supabase-audit-auth-config — 分析认证配置