mcpField
S
supabase-audit-functions

supabase-audit-functions

github.com/yoanbernabeu安全71954 次安装39 周前更新
代码仓库

关于 supabase-audit-functions

此技能用于发现并检查 Supabase Edge Functions 的安全问题,面向执行 Supabase 安全审计的人员。它涵盖函数发现、身份验证、输入验证和错误信息泄露,并要求逐步保存审计记录与证据。

主要功能

  1. 01发现暴露的 Edge Functions
  2. 02检查 JWT 身份验证要求
  3. 03测试输入验证与注入风险
  4. 04检查错误信息泄露
  5. 05逐步保存审计上下文和证据

适用场景

  1. 01盘点项目中可访问的 Edge Functions
  2. 02检查函数是否要求 JWT
  3. 03测试用户输入处理与访问控制
  4. 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 信息泄露)

关键发现:

  1. get-user-data 存在 IDOR——任何用户都可以访问任意用户的数据
  2. admin-panel 缺少角色检查——任何用户都是管理员

优先处理事项:

  1. 修复 get-user-data,验证用户拥有所请求的数据
  2. 在 admin-panel 中添加管理员角色验证
  3. 修复 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 }
  );
}

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

⚠️ 此技能必须在执行过程中逐步更新跟踪文件,而不是只在最后更新。

关键规则:边操作边记录

不要把所有写入操作都推迟到最后。请按以下步骤执行:

  1. 测试每个函数之前 → 将操作记录到 .sb-pentest-audit.log
  2. 发现每个漏洞之后 → 立即更新 .sb-pentest-context.json
  3. 每次函数测试完成之后 → 立即记录结果

这样可以确保即使技能执行被中断、崩溃或超时,截至当时的所有发现也能得到保留。

必需操作(逐步执行)
  1. 更新 .sb-pentest-context.json,写入结果:

    {
      "functions_audit": {
        "timestamp": "...",
        "functions_found": 5,
        "findings": [ ... ]
      }
    }
    
  2. 记录到 .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
    
  3. 如果文件不存在,请在写入前创建文件。

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

强制要求:收集证据

📁 证据目录: .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 — 纳入最终报告

评论

支持 Markdown