名称: supabase-audit-authenticated 描述: 创建一个测试用户(具有明确权限)来审计认证用户可以访问的内容与匿名用户的对比。检测IDOR、跨用户访问和权限提升。
认证用户审计
🔴 关键:需要渐进式文件更新
您必须随着进展写入上下文文件,而不仅仅是在最后。
- 在每次测试后立即写入
.sb-pentest-context.json- 在每次操作之前和之后记录到
.sb-pentest-audit.log- 不要等待技能完成才更新文件
- 如果技能崩溃或被中断,所有先前发现必须已经保存
这不是可选的。未能渐进式写入是一个关键错误。
此技能创建一个测试用户(具有明确权限)来比较认证与匿名访问,并检测IDOR漏洞。
⚠️ 重要:需要用户同意
╔═══════════════════════════════════════════════════════════════════╗
║ 🔐 需要用户创建同意 ║
╠═══════════════════════════════════════════════════════════════════╣
║ ║
║ 此技能将在您的Supabase项目中创建一个测试用户。 ║
║ ║
║ 用户将使用以下信息创建: ║
║ • 邮箱:pentest-[随机]@security-audit.local ║
║ • 密码:强随机密码(32+字符) ║
║ • 目的:测试认证访问与匿名访问 ║
║ ║
║ 审计结束时,您将被询问是否要删除测试用户(推荐)。 ║
║ ║
║ 您是否授权创建测试用户? ║
║ 输入“yes, create test user”以继续。 ║
║ ║
╚═══════════════════════════════════════════════════════════════════╝
没有明确用户同意,请不要继续。
何时使用此技能
- 完成匿名访问测试后
- 检测IDOR(不安全直接对象引用)漏洞
- 测试跨用户数据访问
- 验证RLS策略对认证用户有效
- 查找权限提升问题
先决条件
- 注册必须开放(或使用邀请流程)
- 匿名密钥可用
- 匿名审计已完成(推荐)
为什么认证测试重要
许多漏洞仅在认证时出现:
| 漏洞 | 匿名 | 认证 |
|---|---|---|
| RLS绕过(无RLS) | ✓ 可检测 | ✓ 可检测 |
| IDOR | ✗ 不可见 | ✓ 仅可见 |
| 跨用户访问 | ✗ 不可见 | ✓ 仅可见 |
| 权限提升 | ✗ 不可见 | ✓ 仅可见 |
| 过于宽松的RLS | 部分 | ✓ 完全检测 |
测试用户创建
邮箱格式
pentest-[8字符随机]@security-audit.local
示例:pentest-a7b3c9d2@security-audit.local
密码生成
强密码要求:
- 32+ 字符
- 大写、小写、数字、符号
- 加密随机
示例:Xk9$mP2#vL5@nQ8&jR4*wY7!hT3%bU6^
密码仅显示一次并保存到证据。
执行的测试
1. 用户创建和登录
# 创建用户
curl -X POST "$SUPABASE_URL/auth/v1/signup" \
-H "apikey: $ANON_KEY" \
-H "Content-Type: application/json" \
-d '{"email": "pentest-xxx@security-audit.local", "password": "[STRONG_PASSWORD]"}'
# 登录并获取JWT
curl -X POST "$SUPABASE_URL/auth/v1/token?grant_type=password" \
-H "apikey: $ANON_KEY" \
-H "Content-Type: application/json" \
-d '{"email": "pentest-xxx@security-audit.local", "password": "[STRONG_PASSWORD]"}'
2. 认证与匿名比较
对于每个表:
| 测试 | 匿名 | 认证 | 发现 |
|---|---|---|---|
| SELECT | 0行 | 1,247行 | 🔴 仅认证暴露 |
| 自有数据 | N/A | 仅自有行 | ✅ RLS工作正常 |
| 其他用户数据 | N/A | 所有行 | 🔴 跨用户访问 |
3. IDOR测试
# 作为测试用户,尝试访问其他用户的数据
curl "$SUPABASE_URL/rest/v1/orders?user_id=eq.[OTHER_USER_ID]" \
-H "apikey: $ANON_KEY" \
-H "Authorization: Bearer [TEST_USER_JWT]"
# 如果返回数据:IDOR漏洞!
4. 跨用户访问
# 从JWT获取测试用户ID
TEST_USER_ID=$(echo $JWT | jq -r '.sub')
# 尝试访问属于不同用户的数据
curl "$SUPABASE_URL/rest/v1/profiles?id=neq.$TEST_USER_ID" \
-H "Authorization: Bearer [TEST_USER_JWT]"
# 如果返回其他用户个人资料:跨用户访问!
5. 带认证的存储
# 测试认证存储访问
curl "$SUPABASE_URL/storage/v1/object/list/documents" \
-H "apikey: $ANON_KEY" \
-H "Authorization: Bearer [TEST_USER_JWT]"
# 与匿名结果比较
6. 带认证的实时
// 作为认证用户订阅表变化
const channel = supabase.channel('test')
.on('postgres_changes', {
event: '*',
schema: 'public',
table: 'orders'
}, payload => console.log(payload))
.subscribe()
// 它是否接收到其他用户的订单变化?
输出格式
═══════════════════════════════════════════════════════════
认证用户审计
═══════════════════════════════════════════════════════════
─────────────────────────────────────────────────────────
测试用户创建
─────────────────────────────────────────────────────────
状态:✅ 用户创建成功
测试用户详情:
├── 邮箱:pentest-a7b3c9d2@security-audit.local
├── 用户ID:550e8400-e29b-41d4-a716-446655440099
├── 密码:[保存到证据 - 仅显示一次]
└── JWT获取:✅
─────────────────────────────────────────────────────────
匿名与认证比较
─────────────────────────────────────────────────────────
表:users
├── 匿名访问:0行
├── 认证访问:1,247行 ← 所有用户!
└── 状态:🔴 P0 - 数据对匿名隐藏但暴露给任何认证用户
表:orders
├── 匿名访问:0行(阻止)
├── 认证访问:1行(仅自有订单)
└── 状态:✅ RLS工作正确
表:profiles
├── 匿名访问:0行
├── 认证访问:1,247行 ← 所有个人资料!
├── 仅期望自有个人资料:❌ 否
└── 状态:🔴 P0 - 跨用户个人资料访问
─────────────────────────────────────────────────────────
IDOR测试
─────────────────────────────────────────────────────────
测试:通过ID访问其他用户的订单
├── 请求:GET /orders?user_id=eq.[other-user-id]
├── 认证:测试用户JWT
├── 响应:200 OK - 15个订单返回
└── 状态:🔴 P0 - IDOR漏洞
证明:
curl "$URL/rest/v1/orders?user_id=eq.other-user-uuid" \
-H "Authorization: Bearer [test-user-jwt]"
# 返回属于other-user-uuid的订单!
测试:访问管理端点
├── 请求:GET /functions/v1/admin-panel
├── 认证:测试用户JWT(普通用户)
├── 响应:200 OK - 管理员数据返回!
└── 状态:🔴 P0 - 权限提升
─────────────────────────────────────────────────────────
带认证的存储
─────────────────────────────────────────────────────────
存储桶:documents
├── 匿名:❌ 0个文件(阻止)
├── 认证:✅ 523个文件可见 ← 所有用户的文件!
└── 状态:🔴 P1 - 认证用户看到所有文档
存储桶:user-uploads
├── 匿名:❌ 0个文件
├── 认证:3个文件(仅自有文件)
└── 状态:✅ RLS工作正确
─────────────────────────────────────────────────────────
摘要
─────────────────────────────────────────────────────────
新发现(仅认证):
├── 🔴 P0:users表 - 所有用户对任何认证用户可见
├── 🔴 P0:profiles表 - 跨用户访问
├── 🔴 P0:orders中的IDOR - 可以访问任何用户的订单
├── 🔴 P0:admin-panel中的权限提升
└── 🟠 P1:documents存储桶 - 所有文件对认证用户可见
比较:
├── 发现的问题(匿名):3
├── 发现的问题(认证):8 ← 5个新问题!
└── 仅认证漏洞:5
建议:
这些问题在匿名测试中不可见!
始终使用认证用户进行测试。
─────────────────────────────────────────────────────────
清理
─────────────────────────────────────────────────────────
⚠️ 测试用户仍在数据库中。
您要删除测试用户吗?
邮箱:pentest-a7b3c9d2@security-audit.local
[这需要服务角色密钥或手动删除]
═══════════════════════════════════════════════════════════
上下文输出
{
"authenticated_audit": {
"timestamp": "2025-01-31T12:00:00Z",
"test_user": {
"email": "pentest-a7b3c9d2@security-audit.local",
"user_id": "550e8400-e29b-41d4-a716-446655440099",
"created_at": "2025-01-31T12:00:00Z",
"deleted": false
},
"comparison": {
"tables": {
"users": {
"anon_access": 0,
"auth_access": 1247,
"expected_auth_access": "own_row_only",
"severity": "P0",
"finding": "所有用户对任何认证用户可见"
},
"orders": {
"anon_access": 0,
"auth_access": 1,
"expected_auth_access": "own_rows_only",
"severity": null,
"finding": "RLS工作正确"
}
},
"idor_tests": [
{
"test": "access_other_user_orders",
"vulnerable": true,
"severity": "P0",
"proof": "curl命令..."
}
],
"privilege_escalation": [
{
"endpoint": "/functions/v1/admin-panel",
"vulnerable": true,
"severity": "P0"
}
]
},
"summary": {
"anon_issues": 3,
"auth_issues": 8,
"auth_only_issues": 5
}
}
}
RLS策略示例
正确:用户仅看到自有数据
-- 此RLS策略正确
CREATE POLICY "用户看到自有数据"
ON users FOR SELECT
USING (auth.uid() = id);
-- 结果:
-- 匿名:0行
-- 认证:1行(自有数据)
错误:所有认证用户看到所有内容
-- 此RLS策略错误
CREATE POLICY "认证用户看到所有"
ON users FOR SELECT
USING (auth.role() = 'authenticated'); -- ❌ 过于宽松!
-- 结果:
-- 匿名:0行
-- 认证:所有行 ← 漏洞!
正确修复:
-- 修复:添加用户所有权检查
CREATE POLICY "用户看到自有数据"
ON users FOR SELECT
USING (auth.uid() = id); -- ✅ 仅自有行
清理选项
选项1:手动删除(仪表板)
Supabase仪表板 → 认证 → 用户 → 找到测试用户 → 删除
选项2:通过服务角色密钥(如果可用)
curl -X DELETE "$SUPABASE_URL/auth/v1/admin/users/[USER_ID]" \
-H "apikey: $SERVICE_ROLE_KEY" \
-H "Authorization: Bearer $SERVICE_ROLE_KEY"
选项3:留待后续处理
测试用户使用非功能性邮箱域(security-audit.local),无法被恶意使用。
必需:证据收集
📁 证据目录: .sb-pentest-evidence/05-auth-audit/authenticated-tests/
要创建的证据文件
| 文件 | 内容 |
|---|---|
test-user-created.json |
测试用户详情(密码安全保存) |
anon-vs-auth-comparison.json |
并排比较 |
idor-tests/[table].json |
IDOR测试结果 |
privilege-escalation.json |
权限提升测试 |
证据格式
{
"evidence_id": "AUTH-TEST-001",
"timestamp": "2025-01-31T12:00:00Z",
"category": "auth-audit",
"type": "authenticated_testing",
"test_user": {
"email": "pentest-a7b3c9d2@security-audit.local",
"user_id": "550e8400-...",
"password": "[安全存储 - 不要提交]"
},
"comparison_test": {
"table": "users",
"anonymous": {
"curl_command": "curl '$URL/rest/v1/users' -H 'apikey: $ANON_KEY'",
"response_status": 200,
"rows_returned": 0
},
"authenticated": {
"curl_command": "curl '$URL/rest/v1/users' -H 'apikey: $ANON_KEY' -H 'Authorization: Bearer $JWT'",
"response_status": 200,
"rows_returned": 1247
},
"finding": {
"severity": "P0",
"issue": "所有用户对任何认证用户可见",
"expected": "仅应看到自有行",
"impact": "任何认证用户可进行完整用户枚举"
}
}
}
添加到curl-commands.sh
# === 认证测试 ===
# 注意:用测试用户的JWT替换[JWT]
# 比较匿名与认证访问
curl -s "$SUPABASE_URL/rest/v1/users?select=*&limit=5" -H "apikey: $ANON_KEY"
curl -s "$SUPABASE_URL/rest/v1/users?select=*&limit=5" -H "apikey: $ANON_KEY" -H "Authorization: Bearer [JWT]"
# IDOR测试 - 访问其他用户的数据
curl -s "$SUPABASE_URL/rest/v1/orders?user_id=eq.[OTHER_USER_ID]" \
-H "apikey: $ANON_KEY" \
-H "Authorization: Bearer [JWT]"
# 跨用户个人资料访问
curl -s "$SUPABASE_URL/rest/v1/profiles?id=neq.[TEST_USER_ID]" \
-H "apikey: $ANON_KEY" \
-H "Authorization: Bearer [JWT]"
必需:渐进式上下文文件更新
⚠️ 此技能必须在执行过程中渐进式更新跟踪文件,而不是仅在最后。
关键规则:随进展写入
不要在最后批量所有写入。而是:
- 在用户创建前 → 将同意和操作记录到
.sb-pentest-audit.log - 在用户创建后 → 立即将用户详情保存到上下文和证据
- 在每次比较测试后 → 更新
.sb-pentest-context.json与结果 - 在每次IDOR测试后 → 立即保存证据
这确保如果技能被中断、崩溃或超时,所有截至该点的发现都已保存。
必需操作(渐进式)
-
记录用户创建:
[时间戳] [supabase-audit-authenticated] [同意] 用户授权测试用户创建 [时间戳] [supabase-audit-authenticated] [创建] 测试用户 pentest-xxx@security-audit.local -
立即保存测试用户到上下文:
{ "authenticated_audit": { "test_user": { "email": "...", "user_id": "...", "created_at": "..." } } } -
记录每个发现时:
[时间戳] [supabase-audit-authenticated] [发现] P0:orders表中的IDOR
未能渐进式更新上下文文件是不可接受的。
相关技能
supabase-audit-auth-signup— 首先测试注册是否开放supabase-audit-tables-read— 与匿名结果比较supabase-audit-rls— 深入探讨RLS策略supabase-audit-functions— 使用认证测试函数访问supabase-report— 在报告中包含仅认证发现