关于 supabase-audit-tables-list
用于盘点 Supabase PostgREST API 暴露数据库表的安全审计技能。它从 OpenAPI 模式枚举表和列,并检查模式暴露情况、按风险分类及逐步记录发现。
主要功能
- 01通过 PostgREST OpenAPI 模式枚举表
- 02收集表的模式和列信息
- 03检查非 public 模式的暴露情况
- 04按潜在风险分类并保存证据
- 05逐步更新上下文和审计日志
适用场景
- 01在测试 RLS 策略前了解 API 攻击面
- 02审计项目对外暴露的数据库表和模式
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ yoanbernabeu/ supabase-pentest-skills --skill supabase-audit-tables-list安装后在 Claude Code 中输入/supabase-audit-tables-list确认已加载。
详细介绍
列出已暴露的表
🔴 严重:必须逐步更新文件
你必须边执行边写入上下文文件,不能只在最后写入。
- 每发现一项内容后,立即写入
.sb-pentest-context.json- 每项操作之前和之后,都要记录到
.sb-pentest-audit.log- 不要等到技能执行完毕后才更新文件
- 如果技能崩溃或被中断,所有先前的发现都必须已经保存
这不是可选项。未能逐步写入属于严重错误。
此技能会发现通过 Supabase PostgREST API 暴露的所有数据库表。
何时使用此技能
- 了解 API 攻击面
- 测试 RLS 策略之前
- 清点已暴露的数据模型
- 作为全面安全审计的一部分
前置条件
- 已提取 Supabase URL(如有需要会自动调用)
- 已提取 Anon key(如有需要会自动调用)
工作原理
Supabase 通过 PostgREST 在以下地址暴露表:
https://[project-ref].supabase.co/rest/v1/
此技能使用 OpenAPI 架构端点枚举表:
https://[project-ref].supabase.co/rest/v1/?apikey=[anon-key]
暴露内容
默认情况下,Supabase 会暴露 public 架构中的表。满足以下条件时,表会被暴露:
- 表存在于已暴露的架构中(默认为
public) - 未执行显式的
REVOKE - PostgREST 可以看到这些表
用法
基本表列表
List tables exposed on my Supabase project
包含架构信息
List all exposed tables with column details
输出格式
═══════════════════════════════════════════════════════════
EXPOSED TABLES
═══════════════════════════════════════════════════════════
Project: abc123def.supabase.co
Schema: public
Tables Found: 8
─────────────────────────────────────────────────────────
Table Inventory
─────────────────────────────────────────────────────────
1. users
├── Columns: id, email, name, avatar_url, created_at
├── Primary Key: id (uuid)
├── RLS Status: Unknown (test with supabase-audit-rls)
└── Risk: ⚠️ Contains user PII
2. profiles
├── Columns: id, user_id, bio, website, social_links
├── Primary Key: id (uuid)
├── Foreign Key: user_id → auth.users
└── Risk: ⚠️ Contains user PII
3. posts
├── Columns: id, author_id, title, content, published, created_at
├── Primary Key: id (uuid)
└── Risk: ℹ️ Content data
4. comments
├── Columns: id, post_id, user_id, content, created_at
├── Primary Key: id (uuid)
└── Risk: ℹ️ Content data
5. orders
├── Columns: id, user_id, total, status, items, created_at
├── Primary Key: id (uuid)
└── Risk: 🔴 Contains financial/transaction data
6. products
├── Columns: id, name, description, price, stock, image_url
├── Primary Key: id (uuid)
└── Risk: ℹ️ Public catalog data
7. settings
├── Columns: id, key, value, updated_at
├── Primary Key: id (uuid)
└── Risk: ⚠️ May contain sensitive configuration
8. api_keys
├── Columns: id, user_id, key_hash, name, last_used
├── Primary Key: id (uuid)
└── Risk: 🔴 Contains secrets
─────────────────────────────────────────────────────────
Summary
─────────────────────────────────────────────────────────
Total Tables: 8
High Risk: 2 (orders, api_keys)
Medium Risk: 3 (users, profiles, settings)
Low Risk: 3 (posts, comments, products)
Next Steps:
├── Run supabase-audit-tables-read to test actual data access
├── Run supabase-audit-rls to verify RLS policies
└── Review high-risk tables first
═══════════════════════════════════════════════════════════
风险分类
根据表中可能包含的内容对其分类:
| 风险 | 表模式 | 示例 |
|---|---|---|
| 🔴 高 | 财务、机密、认证 | orders、payments、api_keys、secrets |
| ⚠️ 中 | 用户个人身份信息、配置 | users、profiles、settings、preferences |
| ℹ️ 低 | 公开内容 | posts、products、categories、tags |
上下文输出
{
"tables": {
"count": 8,
"list": [
{
"name": "users",
"schema": "public",
"columns": ["id", "email", "name", "avatar_url", "created_at"],
"primary_key": "id",
"risk_level": "medium",
"risk_reason": "Contains user PII"
},
{
"name": "orders",
"schema": "public",
"columns": ["id", "user_id", "total", "status", "items", "created_at"],
"primary_key": "id",
"risk_level": "high",
"risk_reason": "Contains financial data"
}
],
"by_risk": {
"high": ["orders", "api_keys"],
"medium": ["users", "profiles", "settings"],
"low": ["posts", "comments", "products"]
}
}
}
隐藏表
部分表可能不会出现在 OpenAPI 架构中:
═══════════════════════════════════════════════════════════
ADDITIONAL DISCOVERY
═══════════════════════════════════════════════════════════
Common Tables Not in Schema (testing existence):
├── _prisma_migrations: ❌ Not found
├── schema_migrations: ❌ Not found
├── audit_log: ✅ EXISTS but not in OpenAPI
└── internal_config: ❌ Not found
Note: 'audit_log' exists but may have restricted access.
Test with supabase-audit-tables-read.
═══════════════════════════════════════════════════════════
架构分析
此技能还会检查非公开架构:
Schema Exposure Check:
├── public: ✅ Exposed (8 tables)
├── auth: ❌ Not directly exposed (expected)
├── storage: ❌ Not directly exposed (expected)
├── extensions: ❌ Not exposed (good)
└── custom_schema: ⚠️ Exposed (3 tables) - Review if intentional
常见问题
❌ 问题: 未找到表 ✅ 解决方案:
- 检查 anon key 是否有效
- 确认项目 URL 是否正确
- 项目设置中可能已禁用 API
❌ 问题: 列出的表过多 ✅ 解决方案: 这可能表示架构暴露权限过宽。建议:
-- Restrict exposed schemas
ALTER ROLE anon SET search_path TO public;
❌ 问题: 暴露了敏感表 ✅ 解决方案: 将其从 public 架构中移除,或实施严格的 RLS。
各类表的建议
用户表
-- Ensure RLS is enabled
ALTER TABLE users ENABLE ROW LEVEL SECURITY;
-- Users can only see their own data
CREATE POLICY "Users see own data" ON users
FOR SELECT USING (auth.uid() = id);
订单/支付表
-- Strict RLS for financial data
ALTER TABLE orders ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Users see own orders" ON orders
FOR SELECT USING (auth.uid() = user_id);
-- No public access even for admins via API
-- Use Edge Functions for admin operations
机密表
-- Consider not exposing at all
REVOKE ALL ON TABLE api_keys FROM anon, authenticated;
-- Or use views that hide sensitive columns
CREATE VIEW public.api_keys_safe AS
SELECT id, name, last_used FROM api_keys;
必须:逐步更新上下文文件
⚠️ 此技能必须在执行过程中逐步更新跟踪文件,而不是只在最后更新。
重要规则:边执行边写入
不要将所有写入操作都集中到最后。请按以下步骤执行:
- 开始任何操作之前 → 将操作记录到
.sb-pentest-audit.log - 每发现一张表之后 → 立即更新
.sb-pentest-context.json - 每完成一项重要步骤之后 → 将完成情况记录到
.sb-pentest-audit.log
这样,即使技能被中断、崩溃或超时,此前的所有发现也都能得到保留。
必须执行的操作(逐步进行)
-
使用结果更新
.sb-pentest-context.json:{ "tables": { "count": 8, "list": [ ... ], "by_risk": { "high": [], "medium": [], "low": [] } } } -
记录到
.sb-pentest-audit.log:[TIMESTAMP] [supabase-audit-tables-list] [START] Listing exposed tables [TIMESTAMP] [supabase-audit-tables-list] [SUCCESS] Found 8 tables [TIMESTAMP] [supabase-audit-tables-list] [CONTEXT_UPDATED] .sb-pentest-context.json updated -
如果文件不存在,请先创建文件再写入。
无法接受未更新上下文文件的情况。
必须:收集证据
📁 证据目录: .sb-pentest-evidence/03-api-audit/tables/
需要创建的证据文件
| 文件 | 内容 |
|---|---|
tables-list.json | 已暴露表的完整列表 |
tables-metadata.json | 各表的列详情和类型 |
openapi-schema.json | 原始 OpenAPI/PostgREST 架构 |
证据格式
{
"evidence_id": "API-TBL-001",
"timestamp": "2025-01-31T10:15:00Z",
"category": "api-audit",
"type": "table_enumeration",
"request": {
"method": "GET",
"url": "https://abc123def.supabase.co/rest/v1/",
"headers": {
"apikey": "[REDACTED]"
},
"curl_command": "curl -s 'https://abc123def.supabase.co/rest/v1/' -H 'apikey: $ANON_KEY'"
},
"tables_found": [
{
"name": "users",
"schema": "public",
"columns": ["id", "email", "name", "created_at"],
"primary_key": "id",
"risk_level": "high",
"risk_reason": "Contains PII"
},
{
"name": "orders",
"schema": "public",
"columns": ["id", "user_id", "total", "status"],
"primary_key": "id",
"risk_level": "high",
"risk_reason": "Financial data"
}
],
"summary": {
"total_tables": 8,
"high_risk": 2,
"medium_risk": 3,
"low_risk": 3
}
}
添加到 curl-commands.sh
# === TABLE ENUMERATION ===
# List all exposed tables via OpenAPI schema
curl -s "$SUPABASE_URL/rest/v1/" -H "apikey: $ANON_KEY"
相关技能
supabase-audit-tables-read— 测试实际数据访问权限supabase-audit-rls— 验证 RLS 策略supabase-audit-rpc— 检查已暴露的函数
评论
支持 Markdown