name: supabase-audit-buckets-list description: 列出所有存储桶及其配置,以识别存储攻击面。
列出存储桶
🔴 关键:需要渐进式文件更新
您必须在进行过程中写入上下文文件,而不仅仅是在最后。
- 在发现每个桶后立即写入
.sb-pentest-context.json- 在每个操作前后记录到
.sb-pentest-audit.log- 不要等到技能完成才更新文件
- 如果技能崩溃或中断,所有先前的发现必须已经保存
这不是可选的。未能渐进式写入是严重错误。
这个技能发现Supabase项目中配置的所有存储桶。
何时使用此技能
- 用于盘点所有存储桶
- 在测试桶访问权限之前
- 用于识别公开可访问的桶
- 作为存储安全审计的一部分
先决条件
- Supabase URL和匿名密钥可用
- 检测已完成
理解Supabase存储
Supabase存储提供:
https://[project].supabase.co/storage/v1/
桶可以是:
- 公开:文件无需认证即可访问
- 私有:文件需要认证和RLS策略
存储API端点
| 端点 | 用途 |
|---|---|
/storage/v1/bucket |
列出桶 |
/storage/v1/object/list/[bucket] |
列出桶中的文件 |
/storage/v1/object/[bucket]/[path] |
访问文件 |
/storage/v1/object/public/[bucket]/[path] |
公开文件URL |
用法
基本桶列表
在我的Supabase项目上列出存储桶
带配置详情
列出所有桶及其安全设置
输出格式
═══════════════════════════════════════════════════════════
存储桶
═══════════════════════════════════════════════════════════
项目: abc123def.supabase.co
找到的桶: 5
─────────────────────────────────────────────────────────
桶清单
─────────────────────────────────────────────────────────
1. avatars
├── 公开: ✅ 是
├── 文件大小限制: 1MB
├── 允许的MIME类型: image/jpeg, image/png, image/webp
├── 文件(估计): 1,247
└── 状态: ℹ️ 预期公开桶
公开URL模式:
https://abc123def.supabase.co/storage/v1/object/public/avatars/[文件名]
2. documents
├── 公开: ❌ 否(私有)
├── 文件大小限制: 50MB
├── 允许的MIME类型: application/pdf, application/msword, *
├── 文件(估计): 523
└── 状态: ✅ 私有,需要RLS验证
3. uploads
├── 公开: ✅ 是
├── 文件大小限制: 100MB
├── 允许的MIME类型: */*(任何)
├── 文件(估计): 3,891
└── 状态: 🟠 P1 - 公开且MIME类型不受限制
风险: 任何文件类型都可以上传和访问
建议: 限制允许的MIME类型
4. backups
├── 公开: ✅ 是 ← 意外
├── 文件大小限制: 500MB
├── 允许的MIME类型: */*
├── 文件(估计): 45
└── 状态: 🔴 P0 - 敏感桶公开
风险: 备份文件公开可访问!
立即行动: 更改为私有桶
5. temp
├── 公开: ❌ 否
├── 文件大小限制: 10MB
├── 允许的MIME类型: */*
├── 文件(估计): 12
└── 状态: ✅ 私有临时存储
─────────────────────────────────────────────────────────
总结
─────────────────────────────────────────────────────────
总桶数: 5
公开桶: 3
├── 预期公开: 1 (avatars)
├── P1问题: 1 (uploads - 不受限制的MIME类型)
└── P0关键: 1 (backups - 应为私有)
私有桶: 2
└── 需要使用 supabase-audit-buckets-read 验证RLS
下一步:
├── 修复 'backups' 桶 - 立即设为私有
├── 限制 'uploads' 桶的MIME类型
├── 测试私有桶的RLS
└── 验证公开桶中没有敏感文件
═══════════════════════════════════════════════════════════
桶配置分析
| 配置 | 好 | 坏 |
|---|---|---|
| public: false | ✅ 默认私有 | ❌ public: true 用于敏感数据 |
| fileSizeLimit | ✅ 适当限制 | ❌ 无限制或非常大 |
| allowedMimeTypes | ✅ 限制列表 | ❌ */* 允许任何内容 |
上下文输出
{
"storage": {
"buckets": [
{
"name": "avatars",
"public": true,
"file_size_limit": 1048576,
"allowed_mime_types": ["image/jpeg", "image/png", "image/webp"],
"estimated_files": 1247,
"risk_level": "info",
"expected_public": true
},
{
"name": "backups",
"public": true,
"file_size_limit": 524288000,
"allowed_mime_types": ["*/*"],
"estimated_files": 45,
"risk_level": "P0",
"finding": "敏感桶公开可访问"
}
],
"summary": {
"total": 5,
"public": 3,
"private": 2,
"p0_issues": 1,
"p1_issues": 1
}
}
}
安全建议
对于公开桶
-- 为公开桶创建限制性RLS策略
CREATE POLICY "公开读取头像"
ON storage.objects FOR SELECT
USING (bucket_id = 'avatars');
CREATE POLICY "用户上传自己的头像"
ON storage.objects FOR INSERT
WITH CHECK (
bucket_id = 'avatars'
AND auth.uid()::text = (storage.foldername(name))[1]
);
对于私有桶
-- 仅所有者可以访问自己的文件
CREATE POLICY "用户访问自己的文档"
ON storage.objects FOR ALL
USING (
bucket_id = 'documents'
AND auth.uid()::text = (storage.foldername(name))[1]
);
修复公开备份桶
-- 使桶私有
UPDATE storage.buckets
SET public = false
WHERE name = 'backups';
-- 添加严格RLS
CREATE POLICY "仅管理员访问备份"
ON storage.objects FOR ALL
USING (
bucket_id = 'backups'
AND (SELECT is_admin FROM profiles WHERE id = auth.uid())
);
常见问题
❌ 问题: 无法列出桶 ✅ 解决方案: 存储API可能受限。这实际上是良好的安全措施。记录为“无法枚举”。
❌ 问题: 发现许多桶 ✅ 解决方案: 大型应用可能有许多桶。首先关注公开桶。
❌ 问题: 桶计数与预期不符 ✅ 解决方案: 某些桶可能动态创建。检查应用代码。
强制:渐进式上下文文件更新
⚠️ 此技能必须在执行过程中渐进式更新跟踪文件,而不是仅在最后。
关键规则:边进行边写入
不要在最后批量写入所有内容。而是:
- 在开始桶枚举之前 → 将操作记录到
.sb-pentest-audit.log - 在每个桶发现后 → 立即更新
.sb-pentest-context.json - 在每个配置分析后 → 记录结果
这确保如果技能中断、崩溃或超时,所有到该点的发现都得以保留。
必需操作(渐进式)
-
更新
.sb-pentest-context.json与结果:{ "storage": { "buckets": [ ... ], "summary": { "total": 5, "public": 3, "private": 2 } } } -
记录到
.sb-pentest-audit.log:[时间戳] [supabase-audit-buckets-list] [开始] 列出存储桶 [时间戳] [supabase-audit-buckets-list] [成功] 找到5个桶 [时间戳] [supabase-audit-buckets-list] [上下文更新] .sb-pentest-context.json 已更新 -
如果文件不存在,在写入前创建它们。
未能更新上下文文件是不可接受的。
强制:证据收集
📁 证据目录: .sb-pentest-evidence/04-storage-audit/
要创建的证据文件
| 文件 | 内容 |
|---|---|
buckets-config.json |
所有桶配置 |
buckets/[名称]/file-list.json |
每个桶的文件列表 |
证据格式
{
"evidence_id": "STG-LIST-001",
"timestamp": "2025-01-31T10:35:00Z",
"category": "storage-audit",
"type": "bucket_enumeration",
"request": {
"method": "GET",
"url": "https://abc123def.supabase.co/storage/v1/bucket",
"curl_command": "curl -s '$URL/storage/v1/bucket' -H 'apikey: $ANON_KEY' -H 'Authorization: Bearer $ANON_KEY'"
},
"buckets": [
{
"name": "avatars",
"public": true,
"file_size_limit": 1048576,
"allowed_mime_types": ["image/jpeg", "image/png"],
"risk_level": "info",
"assessment": "适用于公开头像"
},
{
"name": "backups",
"public": true,
"file_size_limit": 524288000,
"allowed_mime_types": ["*/*"],
"risk_level": "P0",
"assessment": "关键:备份桶不应公开"
}
],
"summary": {
"total_buckets": 5,
"public_buckets": 3,
"private_buckets": 2,
"critical_misconfigurations": 1
}
}
添加到 curl-commands.sh
# === 存储桶枚举 ===
# 列出所有桶
curl -s "$SUPABASE_URL/storage/v1/bucket" \
-H "apikey: $ANON_KEY" \
-H "Authorization: Bearer $ANON_KEY"
# 列出特定桶中的文件
curl -s "$SUPABASE_URL/storage/v1/object/list/backups" \
-H "apikey: $ANON_KEY" \
-H "Authorization: Bearer $ANON_KEY"
相关技能
supabase-audit-buckets-read— 尝试读取文件supabase-audit-buckets-public— 查找配置不当的公开桶supabase-audit-storage-rls— 测试存储RLS策略