Supabase存储桶文件访问审计Skill supabase-audit-buckets-read

此技能用于对Supabase存储桶进行文件访问测试,验证存储权限控制,检测敏感文件暴露,适用于云存储安全审计和渗透测试。关键词包括Supabase、存储桶、文件访问、安全审计、渗透测试、云安全。

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

name: supabase-audit-buckets-read description: 尝试列出和读取存储桶中的文件以验证访问控制。

存储桶文件访问测试

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

您必须在执行过程中写入上下文文件,而不仅仅是在结束时。

  • 在测试每个存储桶后,立即写入 .sb-pentest-context.json
  • 在每次文件访问测试前后记录到 .sb-pentest-audit.log
  • 不要等待技能完成才更新文件
  • 如果技能崩溃或中断,所有先前发现必须已保存

这不是可选的。未进行渐进式写入是关键错误。

此技能测试存储桶中的实际文件访问以验证权限。

何时使用此技能

  • 列出存储桶后,以验证实际访问
  • 测试存储RLS策略有效性
  • 检查敏感文件暴露
  • 记录可访问的文件

先决条件

  • 已列出存储桶(如果需要则自动调用)
  • 匿名密钥可用

工作原理

技能尝试:

  1. 列出每个存储桶中的文件
  2. 读取文件元数据
  3. 下载示例文件(用于内容类型验证)
  4. 检查公共URL访问

重要: 这是只读操作。不会修改或删除文件。

测试方法

存储桶类型 执行的测试
公共 直接URL访问、列出、元数据
私有 使用匿名密钥的API列出、认证访问

使用

基本读取测试

测试存储桶的读取访问

特定存储桶

测试文档存储桶的文件访问

仅列出(不下载)

列出可访问的文件,不下载内容

输出格式

═══════════════════════════════════════════════════════════
 存储桶文件访问测试
═══════════════════════════════════════════════════════════

 项目:abc123def.supabase.co
 测试存储桶:5

 ─────────────────────────────────────────────────────────
 avatars(公共存储桶)
 ─────────────────────────────────────────────────────────

 状态:✅ 预期访问
 找到文件:1,247

 示例文件:
 ├── user-550e8400.jpg(45KB)- 公共URL有效
 ├── user-6ba7b810.png(32KB)- 公共URL有效
 └── default.png(12KB)- 公共URL有效

 访问方法:
 ├── 公共URL:✅ 可访问
 ├── API列出:✅ 有效
 └── 元数据:✅ 可见

 评估:头像存储的预期行为。

 ─────────────────────────────────────────────────────────
 documents(私有存储桶)
 ─────────────────────────────────────────────────────────

 状态:✅ 正确保护
 找到文件:0(通过匿名密钥)

 访问方法:
 ├── 公共URL:❌ 403禁止(正确)
 ├── API列出:❌ 空结果(RLS工作)
 └── 元数据:❌ 不可访问(正确)

 评估:RLS策略工作正确。

 ─────────────────────────────────────────────────────────
 uploads(公共存储桶)
 ─────────────────────────────────────────────────────────

 状态:🟠 P1 - 敏感文件暴露
 找到文件:3,891

 检测到的敏感文件:
 ├── 🔴 invoice-2025-001.pdf - 包含财务数据
 ├── 🔴 contract-signed.pdf - 法律文档
 ├── 🔴 id-verification.jpg - 个人身份证照片!
 ├── ⚠️ database-export.csv - 可能的数据导出
 └── ⚠️ config.json - 配置文件

 文件类型分布:
 ├── PDF:1,234(31%)
 ├── 图像:2,100(54%)
 ├── 文档:450(12%)
 └── 其他:107(3%)

 评估:存储桶包含不应公开的敏感文件!

 ─────────────────────────────────────────────────────────
 backups(公共 - 关键)
 ─────────────────────────────────────────────────────────

 状态:🔴 P0 - 关键数据暴露
 找到文件:45

 暴露的文件:
 ├── 🔴 db-backup-2025-01-30.sql(125MB)- 数据库备份!
 ├── 🔴 db-backup-2025-01-29.sql(124MB)- 数据库备份!
 ├── 🔴 users-export.csv(2.3MB)- 用户数据导出!
 ├── 🔴 secrets.env(1KB)- 环境秘密!
 └── 🔴 .env.production(1KB)- 生产秘密!

 示例内容(secrets.env):
 ┌─────────────────────────────────────────────────────────┐
 │ STRIPE_SECRET_KEY=sk_live_xxxxxxxxxxxx                 │
 │ DATABASE_URL=postgresql://postgres:xxx@...             │
 │ JWT_SECRET=super-secret-jwt-key                        │
 └─────────────────────────────────────────────────────────┘

 ⚠️ 立即行动要求:
 1. 立即使存储桶私有
 2. 轮换所有暴露的秘密
 3. 从公共访问中删除备份文件
 4. 在日志中审计未经授权的访问

 ─────────────────────────────────────────────────────────
 temp(私有存储桶)
 ─────────────────────────────────────────────────────────

 状态:✅ 正确保护
 找到文件:0(通过匿名密钥)
 评估:访问正确受限。

 ─────────────────────────────────────────────────────────
 摘要
 ─────────────────────────────────────────────────────────

 P0关键:1个存储桶(backups - 数据库转储和秘密暴露)
 P1高:1个存储桶(uploads - 公共存储桶中的敏感文档)
 受保护:2个存储桶(documents, temp)
 预期:1个存储桶(avatars)

 可访问文件总数:5,183
 暴露敏感文件:52
 暴露秘密文件:3

 立即行动:
 1. 🔴 删除或使'backups'存储桶私有
 2. 🔴 轮换Stripe密钥、数据库密码、JWT秘密
 3. 🟠 将敏感文件从'uploads'移动到私有存储桶
 4. 审查所有52个敏感文件的暴露影响

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

敏感文件检测

技能通过以下方式识别敏感文件:

文件名模式

模式 风险 类型
*.sql, backup* P0 数据库转储
.env*, *secrets* P0 秘密文件
*password*, *credential* P0 凭据
*invoice*, *payment* P1 财务
*contract*, *agreement* P1 法律
*id*, *passport*, *license* P1 身份
*export*, *dump* P1 数据导出

内容检测

对于可访问文件,技能采样内容以检测:

  • API密钥(如sk_live_pk_test_模式)
  • 数据库凭据
  • JWT秘密
  • 个人信息模式

上下文输出

{
  "storage_access": {
    "timestamp": "2025-01-31T11:30:00Z",
    "buckets_tested": 5,
    "findings": [
      {
        "bucket": "backups",
        "severity": "P0",
        "public": true,
        "files_exposed": 45,
        "sensitive_files": [
          {
            "path": "db-backup-2025-01-30.sql",
            "size": 131072000,
            "type": "database_backup",
            "risk": "完整数据库可访问"
          },
          {
            "path": "secrets.env",
            "size": 1024,
            "type": "secrets",
            "exposed_secrets": ["STRIPE_SECRET_KEY", "DATABASE_URL", "JWT_SECRET"]
          }
        ]
      }
    ],
    "summary": {
      "total_files_accessible": 5183,
      "sensitive_files": 52,
      "secret_files": 3
    }
  }
}

修复步骤

针对暴露的秘密

# 1. 轮换Stripe密钥
# Stripe仪表板 → 开发者 → API密钥 → 滚动密钥

# 2. 更改数据库密码
# Supabase仪表板 → 设置 → 数据库 → 重置密码

# 3. 重新生成JWT秘密
# Supabase仪表板 → 设置 → API → 重新生成JWT秘密

# 4. 更新应用程序环境变量
# 使用新秘密重新部署

针对公共存储桶修复

-- 使存储桶私有
UPDATE storage.buckets
SET public = false
WHERE name = 'backups';

-- 删除敏感文件或移动到安全位置
DELETE FROM storage.objects
WHERE bucket_id = 'backups';

针对上传存储桶

-- 添加RLS以限制访问
CREATE POLICY "用户访问自己的上传"
  ON storage.objects FOR ALL
  USING (
    bucket_id = 'uploads'
    AND auth.uid()::text = (storage.foldername(name))[1]
  );

常见问题

问题: 无法列出私有存储桶中的文件 ✅ 解决方案: 这是正确行为。RLS工作正常。

问题: 大量文件需要扫描 ✅ 解决方案: 对大存储桶使用采样模式。

问题: 文件下载失败 ✅ 解决方案: 可能是RLS限制或网络问题。

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

⚠️ 此技能必须在执行过程中渐进式更新跟踪文件,而不是仅在结束时。

关键规则:边执行边写入

不要将所有写入批量处理在结束时。相反:

  1. 在测试每个存储桶前 → 将操作记录到.sb-pentest-audit.log
  2. 在发现每个敏感文件后 → 立即更新.sb-pentest-context.json
  3. 在每个存储桶完成后 → 记录摘要

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

必需操作(渐进式)

  1. 更新.sb-pentest-context.json 与结果:

    {
      "storage_access": {
        "timestamp": "...",
        "buckets_tested": 5,
        "findings": [ ... ],
        "summary": { "total_files_accessible": 5183, ... }
      }
    }
    
  2. 记录到.sb-pentest-audit.log

    [时间戳] [supabase-audit-buckets-read] [开始] 测试存储桶文件访问
    [时间戳] [supabase-audit-buckets-read] [发现] P0: backups存储桶有暴露的秘密
    [时间戳] [supabase-audit-buckets-read] [上下文更新] .sb-pentest-context.json已更新
    
  3. 如果文件不存在,在写入前创建它们。

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

强制:证据收集

📁 证据目录: .sb-pentest-evidence/04-storage-audit/buckets/

创建的证据文件

文件 内容
buckets/[名称]/file-list.json 在存储桶中找到的文件
buckets/[名称]/sensitive-files.json 检测到的敏感文件
buckets/[名称]/sample-contents/ 脱敏内容样本

证据格式(敏感文件暴露)

{
  "evidence_id": "STG-READ-001",
  "timestamp": "2025-01-31T10:40:00Z",
  "category": "storage-audit",
  "type": "file_access",
  "severity": "P0",

  "bucket": "backups",
  "public": true,

  "files_found": 45,
  "sensitive_files": [
    {
      "path": "db-backup-2025-01-30.sql",
      "size": 131072000,
      "type": "database_backup",
      "public_url": "https://abc123def.supabase.co/storage/v1/object/public/backups/db-backup-2025-01-30.sql",
      "curl_command": "curl -o backup.sql 'https://abc123def.supabase.co/storage/v1/object/public/backups/db-backup-2025-01-30.sql'"
    },
    {
      "path": "secrets.env",
      "size": 1024,
      "type": "secrets_file",
      "content_sample": "STRIPE_SECRET_KEY=sk_live_[脱敏]
DATABASE_URL=postgresql://[脱敏]",
      "exposed_secrets": ["STRIPE_SECRET_KEY", "DATABASE_URL", "JWT_SECRET"]
    }
  ],

  "impact": {
    "data_breach": true,
    "secrets_exposed": true,
    "affected_records": "所有数据库记录",
    "credentials_to_rotate": ["Stripe API密钥", "数据库密码", "JWT秘密"]
  }
}

添加到curl-commands.sh

# === 存储文件访问测试 ===
# 列出backups存储桶中的文件
curl -s "$SUPABASE_URL/storage/v1/object/list/backups" \
  -H "apikey: $ANON_KEY"

# 直接访问公共文件(如果可访问则为P0)
curl -I "https://abc123def.supabase.co/storage/v1/object/public/backups/secrets.env"

# 下载暴露的备份(用于证据 - 注意大小)
# curl -o evidence-backup-sample.sql "https://abc123def.supabase.co/storage/v1/object/public/backups/db-backup-2025-01-30.sql" | head -1000

相关技能

  • supabase-audit-buckets-list — 首先列出存储桶
  • supabase-audit-buckets-public — 关注公共访问问题
  • supabase-report — 生成完整报告