关于 supabase-audit-functions
此技能用于发现并检查 Supabase Edge Functions 的安全问题,面向执行 Supabase 安全审计的人员。它涵盖函数发现、身份验证、输入验证和错误信息泄露,并要求逐步保存审计记录与证据。
主要功能
- 01发现暴露的 Edge Functions
- 02检查 JWT 身份验证要求
- 03测试输入验证与注入风险
- 04检查错误信息泄露
- 05逐步保存审计上下文和证据
适用场景
- 01盘点项目中可访问的 Edge Functions
- 02检查函数是否要求 JWT
- 03测试用户输入处理与访问控制
- 04审查函数错误响应是否泄露信息
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ yoanbernabeu/ supabase-pentest-skills --skill supabase-audit-functions安装后在 Claude Code 中输入/supabase-audit-functions确认已加载。
详细介绍
Edge Functions 审计
🔴 严重:必须逐步更新文件
必须在操作过程中写入上下文文件,不能只在最后写入。
- 每测试完一个函数,立即写入
.sb-pentest-context.json- 每次函数测试之前和之后,都要记录到
.sb-pentest-audit.log- 不要等到技能完成后才更新文件
- 如果技能崩溃或中断,所有先前的发现都必须已保存
这不是可选项。未能逐步写入是严重错误。
此技能用于发现和测试 Supabase Edge Functions 中的安全问题。
适用场景
- 发现暴露的 Edge Functions
- 测试函数的身份验证要求
- 检查输入验证问题
- 作为全面安全审计的一部分
前置条件
- 已获取 Supabase URL
- 已完成检测
了解 Edge Functions
Supabase Edge Functions 是基于 Deno 的无服务器函数:
https://[project].supabase.co/functions/v1/[function-name]
| 安全方面 | 注意事项 |
|---|---|
| 身份验证 | 函数可以要求 JWT,也可以公开访问 |
| CORS | 跨源访问控制 |
| 输入验证 | 用户输入处理 |
| 密钥 | 环境变量暴露 |
执行的测试
| 测试 | 目的 |
|---|---|
| 函数发现 | 查找暴露的函数 |
| 身份验证要求 | 检查是否要求 JWT |
| 输入验证 | 测试注入问题 |
| 错误处理 | 检查信息泄露 |
用法
基本函数审计
Audit Edge Functions on my Supabase project
测试指定函数
Test the process-payment Edge Function for security issues
输出格式
═══════════════════════════════════════════════════════════
EDGE FUNCTIONS AUDIT
═══════════════════════════════════════════════════════════
Project: abc123def.supabase.co
Endpoint: https://abc123def.supabase.co/functions/v1/
─────────────────────────────────────────────────────────
Function Discovery
─────────────────────────────────────────────────────────
Discovery Method: Common name enumeration + client code analysis
Functions Found: 5
─────────────────────────────────────────────────────────
1. hello-world
─────────────────────────────────────────────────────────
Endpoint: /functions/v1/hello-world
Method: GET, POST
Authentication Test:
├── Without JWT: ✅ 200 OK
└── Status: ℹ️ Public function (no auth required)
Response:
```json
{"message": "Hello, World!"}
评估:✅ 适当 简单的公共端点,不涉及敏感操作。
───────────────────────────────────────────────────────── 2. process-payment ─────────────────────────────────────────────────────────
端点:/functions/v1/process-payment 方法:POST
身份验证测试: ├── 不带 JWT:❌ 401 Unauthorized ├── 携带有效 JWT:✅ 200 OK └── 状态:✅ 需要身份验证
输入验证测试: ├── 缺少 amount:❌ 400 Bad Request(良好) ├── amount 为负数:❌ 400 Bad Request(良好) ├── amount 为字符串:❌ 400 Bad Request(良好) └── 有效输入:✅ 200 OK
错误响应测试: ├── 错误格式:通用消息(良好) └── 堆栈跟踪:❌ 未暴露(良好)
评估:✅ 安全性良好 需要身份验证,会验证输入,并安全地处理错误。
───────────────────────────────────────────────────────── 3. get-user-data ─────────────────────────────────────────────────────────
端点:/functions/v1/get-user-data 方法:GET
身份验证测试: ├── 不带 JWT:❌ 401 Unauthorized └── 状态:✅ 需要身份验证
授权测试: ├── 请求自己的数据:✅ 200 OK ├── 请求其他用户的数据:✅ 200 OK ← 🔴 P0! └── 状态:🔴 访问控制失效
测试:
# As user A, request user B's data
curl https://abc123def.supabase.co/functions/v1/get-user-data?user_id=user-b-id \
-H "Authorization: Bearer [user-a-token]"
# Returns user B's data!
发现:🔴 P0 - IDOR 漏洞 函数接受 user_id 参数,却未验证 经过身份验证的用户请求的是否是自己的数据。
修复:
// In Edge Function
const { user_id } = await req.json();
const jwt_user = getUser(req); // From JWT
// Verify ownership
if (user_id !== jwt_user.id) {
return new Response('Forbidden', { status: 403 });
}
───────────────────────────────────────────────────────── 4. admin-panel ─────────────────────────────────────────────────────────
端点:/functions/v1/admin-panel 方法:GET、POST
身份验证测试: ├── 不带 JWT:❌ 401 Unauthorized ├── 携带普通用户 JWT:✅ 200 OK ← 🔴 P0! └── 状态:🔴 缺少角色检查
发现:🔴 P0 - 权限提升 任何经过身份验证的用户都可以访问管理函数。 函数代码中没有角色验证。
修复:
// Verify admin role
const user = getUser(req);
const { data: profile } = await supabase
.from('profiles')
.select('is_admin')
.eq('id', user.id)
.single();
if (!profile?.is_admin) {
return new Response('Forbidden', { status: 403 });
}
───────────────────────────────────────────────────────── 5. webhook-handler ─────────────────────────────────────────────────────────
端点:/functions/v1/webhook-handler 方法:POST
身份验证测试: ├── 不带 JWT:✅ 200 OK(webhook 的预期行为) └── 状态:ℹ️ 公开(webhook 端点通常是公开的)
Webhook 安全测试: ├── 签名验证:⚠️ 无法测试(需要有效签名) └── 速率限制:未知
错误响应测试:
{
"error": "Invalid signature",
"expected": "sha256=abc123...",
"received": "sha256=xyz789..."
}
发现:🟠 P1 - 信息泄露 错误响应泄露了预期的签名格式。 这可能会帮助攻击者了解验证机制。
修复:
// Generic error, log details server-side
if (!validSignature) {
console.error(`Invalid signature: expected ${expected}, got ${received}`);
return new Response('Unauthorized', { status: 401 });
}
───────────────────────────────────────────────────────── 总结 ─────────────────────────────────────────────────────────
发现的函数:5 个
安全评估: ├── ✅ 安全:2 个(hello-world、process-payment) ├── 🔴 P0:2 个(get-user-data 存在 IDOR、admin-panel 存在权限提升) └── 🟠 P1:1 个(webhook-handler 信息泄露)
关键发现:
- get-user-data 存在 IDOR——任何用户都可以访问任意用户的数据
- admin-panel 缺少角色检查——任何用户都是管理员
优先处理事项:
- 修复 get-user-data,验证用户拥有所请求的数据
- 在 admin-panel 中添加管理员角色验证
- 修复 webhook-handler 的错误消息
═══════════════════════════════════════════════════════════
## Common Function Vulnerabilities
| Vulnerability | Description | Severity |
|---------------|-------------|----------|
| No auth | Function accessible without JWT | P0-P2 |
| IDOR | User can access other users' data | P0 |
| Missing role check | Regular user accesses admin functions | P0 |
| Input injection | User input not validated | P0-P1 |
| Info disclosure | Errors reveal internal details | P1-P2 |
| CORS misconfigured | Accessible from unintended origins | P1-P2 |
## Function Discovery Methods
### 1. Client Code Analysis
```javascript
// Look for function invocations in client code
supabase.functions.invoke('function-name', {...})
fetch('/functions/v1/function-name', {...})
2. 常见名称枚举
已测试的函数名称:
- hello-world、hello、test
- process-payment、payment、checkout
- get-user-data、user、profile
- admin、admin-panel、dashboard
- webhook、webhook-handler、stripe-webhook
- send-email、notify、notification
3. 错误响应分析
404 Not Found → Function doesn't exist
401 Unauthorized → Function exists, needs auth
200 OK → Function exists, accessible
上下文输出
{
"functions_audit": {
"timestamp": "2025-01-31T14:30:00Z",
"functions_found": 5,
"findings": [
{
"function": "get-user-data",
"severity": "P0",
"vulnerability": "IDOR",
"description": "Any authenticated user can access any user's data",
"remediation": "Verify user owns requested resource"
},
{
"function": "admin-panel",
"severity": "P0",
"vulnerability": "Privilege Escalation",
"description": "No role check, any authenticated user is admin",
"remediation": "Add admin role verification"
}
]
}
}
安全函数模式
身份验证检查
import { createClient } from '@supabase/supabase-js'
Deno.serve(async (req) => {
// Get JWT from header
const authHeader = req.headers.get('Authorization');
if (!authHeader) {
return new Response('Unauthorized', { status: 401 });
}
// Verify JWT with Supabase
const supabase = createClient(
Deno.env.get('SUPABASE_URL')!,
Deno.env.get('SUPABASE_ANON_KEY')!,
{ global: { headers: { Authorization: authHeader } } }
);
const { data: { user }, error } = await supabase.auth.getUser();
if (error || !user) {
return new Response('Unauthorized', { status: 401 });
}
// User is authenticated
// ...
});
授权检查(防止 IDOR)
// For user-specific resources
const requestedUserId = body.user_id;
const authenticatedUserId = user.id;
if (requestedUserId !== authenticatedUserId) {
return new Response('Forbidden', { status: 403 });
}
角色检查(管理员)
// Check admin role
const { data: profile } = await supabase
.from('profiles')
.select('role')
.eq('id', user.id)
.single();
if (profile?.role !== 'admin') {
return new Response('Forbidden', { status: 403 });
}
输入验证
import { z } from 'zod';
const PaymentSchema = z.object({
amount: z.number().positive().max(10000),
currency: z.enum(['usd', 'eur', 'gbp']),
description: z.string().max(200).optional()
});
// Validate input
const result = PaymentSchema.safeParse(body);
if (!result.success) {
return new Response(
JSON.stringify({ error: 'Invalid input' }),
{ status: 400 }
);
}
强制要求:渐进式更新上下文文件
⚠️ 此技能必须在执行过程中逐步更新跟踪文件,而不是只在最后更新。
关键规则:边操作边记录
不要把所有写入操作都推迟到最后。请按以下步骤执行:
- 测试每个函数之前 → 将操作记录到
.sb-pentest-audit.log - 发现每个漏洞之后 → 立即更新
.sb-pentest-context.json - 每次函数测试完成之后 → 立即记录结果
这样可以确保即使技能执行被中断、崩溃或超时,截至当时的所有发现也能得到保留。
必需操作(逐步执行)
-
更新
.sb-pentest-context.json,写入结果:{ "functions_audit": { "timestamp": "...", "functions_found": 5, "findings": [ ... ] } } -
记录到
.sb-pentest-audit.log:[TIMESTAMP] [supabase-audit-functions] [START] Auditing Edge Functions [TIMESTAMP] [supabase-audit-functions] [FINDING] P0: IDOR in get-user-data [TIMESTAMP] [supabase-audit-functions] [CONTEXT_UPDATED] .sb-pentest-context.json updated -
如果文件不存在,请在写入前创建文件。
不更新上下文文件是不可接受的。
强制要求:收集证据
📁 证据目录: .sb-pentest-evidence/07-functions-audit/
需要创建的证据文件
| 文件 | 内容 |
|---|---|
discovered-functions.json | 已发现的 Edge Functions 列表 |
function-tests/[name].json | 每个函数的测试结果 |
证据格式(IDOR 漏洞)
{
"evidence_id": "FN-001",
"timestamp": "2025-01-31T11:10:00Z",
"category": "functions-audit",
"type": "idor_vulnerability",
"severity": "P0",
"function": "get-user-data",
"endpoint": "https://abc123def.supabase.co/functions/v1/get-user-data",
"tests": [
{
"test_name": "auth_required",
"request": {
"method": "GET",
"headers": {},
"curl_command": "curl '$URL/functions/v1/get-user-data'"
},
"response": {"status": 401},
"result": "PASS"
},
{
"test_name": "idor_test",
"description": "As user A, request user B's data",
"request": {
"method": "GET",
"url": "$URL/functions/v1/get-user-data?user_id=user-b-id",
"headers": {"Authorization": "Bearer [USER_A_TOKEN]"},
"curl_command": "curl '$URL/functions/v1/get-user-data?user_id=user-b-id' -H 'Authorization: Bearer [USER_A_TOKEN]'"
},
"response": {
"status": 200,
"body": {"id": "user-b-id", "email": "[REDACTED]", "data": "[REDACTED]"}
},
"result": "VULNERABLE",
"impact": "Any authenticated user can access any other user's data"
}
],
"remediation": "Add ownership check: if (user_id !== jwt_user.id) return 403"
}
证据格式(权限提升)
{
"evidence_id": "FN-002",
"timestamp": "2025-01-31T11:15:00Z",
"category": "functions-audit",
"type": "privilege_escalation",
"severity": "P0",
"function": "admin-panel",
"test": {
"description": "Regular user accessing admin function",
"request": {
"method": "GET",
"headers": {"Authorization": "Bearer [REGULAR_USER_TOKEN]"},
"curl_command": "curl '$URL/functions/v1/admin-panel' -H 'Authorization: Bearer [REGULAR_USER_TOKEN]'"
},
"response": {
"status": 200,
"body": {"admin_data": "[REDACTED]"}
},
"result": "VULNERABLE",
"impact": "Any authenticated user has admin access"
}
}
相关技能
supabase-audit-rpc— 数据库函数(不同于 Edge Functions)supabase-audit-auth-config— 身份验证配置supabase-report— 纳入最终报告