SupabaseEdgeFunctions安全审计Skill supabase-audit-functions

这个技能专为安全审计设计,用于自动发现和测试Supabase Edge Functions的安全漏洞、认证问题、输入验证错误等,适用于渗透测试、云安全审计和DevOps安全实践。关键词:Supabase, Edge Functions, 安全审计, 漏洞检测, 云安全, 渗透测试, 无服务器安全。

安全审计 0 次安装 0 次浏览 更新于 3/18/2026

name: supabase-audit-functions description: 发现和测试Supabase Edge 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
输入验证 测试注入漏洞
错误处理 检查信息泄露

用法

基本函数审计

审计我的Supabase项目上的Edge Functions

测试特定函数

测试process-payment Edge Function的安全问题

输出格式

═══════════════════════════════════════════════════════════
 EDGE FUNCTIONS 审计
═══════════════════════════════════════════════════════════

 项目:abc123def.supabase.co
 端点:https://abc123def.supabase.co/functions/v1/

 ─────────────────────────────────────────────────────────
 函数发现
 ─────────────────────────────────────────────────────────

 发现方法:常见名称枚举 + 客户端代码分析

 找到的函数:5

 ─────────────────────────────────────────────────────────
 1. hello-world
 ─────────────────────────────────────────────────────────

 端点:/functions/v1/hello-world
 方法:GET, POST

 认证测试:
 ├── 无JWT:✅ 200 OK
 └── 状态:ℹ️ 公共函数(无需认证)

 响应:
 ```json
 {"message": "Hello, World!"}

评估:✅ 适当 简单公共端点,无敏感操作。

───────────────────────────────────────────────────────── 2. process-payment ─────────────────────────────────────────────────────────

端点:/functions/v1/process-payment 方法:POST

认证测试: ├── 无JWT:❌ 401 Unauthorized ├── 有效JWT:✅ 200 OK └── 状态:✅ 需要认证

输入验证测试: ├── 缺少金额:❌ 400 Bad Request(良好) ├── 负金额:❌ 400 Bad Request(良好) ├── 字符串金额:❌ 400 Bad Request(良好) └── 有效输入:✅ 200 OK

错误响应测试: ├── 错误格式:通用消息(良好) └── 堆栈跟踪:❌ 未暴露(良好)

评估:✅ 正确保护 需要认证,验证输入,安全错误处理。

───────────────────────────────────────────────────────── 3. get-user-data ─────────────────────────────────────────────────────────

端点:/functions/v1/get-user-data 方法:GET

认证测试: ├── 无JWT:❌ 401 Unauthorized └── 状态:✅ 需要认证

授权测试: ├── 请求自身数据:✅ 200 OK ├── 请求其他用户数据:✅ 200 OK ← 🔴 P0! └── 状态:🔴 访问控制损坏

测试:

# 以用户A身份,请求用户B的数据
curl https://abc123def.supabase.co/functions/v1/get-user-data?user_id=user-b-id \
  -H "Authorization: Bearer [user-a-token]"

# 返回用户B的数据!

发现:🔴 P0 - IDOR漏洞 函数接受user_id参数,未验证认证用户是否请求自身数据。

修复:

// 在Edge Function中
const { user_id } = await req.json();
const jwt_user = getUser(req); // 从JWT

// 验证所有权
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 - 权限提升 任何认证用户均可访问管理员功能。函数代码中无角色验证。

修复:

// 验证管理员角色
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(webhooks通常为公共) └── 状态:ℹ️ 公共(webhook端点通常公开)

Webhook安全测试: ├── 签名验证:⚠️ 无法测试(需要有效签名) └── 速率限制:未知

错误响应测试:

{
  "error": "Invalid signature",
  "expected": "sha256=abc123...",
  "received": "sha256=xyz789..."
}

发现:🟠 P1 - 信息泄露 错误响应揭示预期签名格式。可能帮助攻击者理解验证机制。

修复:

// 通用错误,在服务器端记录详情
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错误消息

═══════════════════════════════════════════════════════════


## 常见函数漏洞

| 漏洞 | 描述 | 严重性 |
|---------------|-------------|----------|
| 无认证 | 函数无需JWT可访问 | P0-P2 |
| IDOR | 用户可访问其他用户数据 | P0 |
| 缺少角色检查 | 普通用户访问管理员功能 | P0 |
| 输入注入 | 用户输入未验证 | P0-P1 |
| 信息泄露 | 错误揭示内部细节 | P1-P2 |
| CORS配置错误 | 可从非预期来源访问 | P1-P2 |

## 函数发现方法

### 1. 客户端代码分析

```javascript
// 在客户端代码中查找函数调用
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 → 函数不存在
401 Unauthorized → 函数存在,需要认证
200 OK → 函数存在,可访问

上下文输出

{
  "functions_audit": {
    "timestamp": "2025-01-31T14:30:00Z",
    "functions_found": 5,
    "findings": [
      {
        "function": "get-user-data",
        "severity": "P0",
        "vulnerability": "IDOR",
        "description": "任何认证用户可访问任何用户数据",
        "remediation": "验证用户拥有请求资源"
      },
      {
        "function": "admin-panel",
        "severity": "P0",
        "vulnerability": "权限提升",
        "description": "无角色检查,任何认证用户成为管理员",
        "remediation": "添加管理员角色验证"
      }
    ]
  }
}

安全函数模式

认证检查

import { createClient } from '@supabase/supabase-js'

Deno.serve(async (req) => {
  // 从头部获取JWT
  const authHeader = req.headers.get('Authorization');
  if (!authHeader) {
    return new Response('Unauthorized', { status: 401 });
  }

  // 使用Supabase验证JWT
  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 });
  }

  // 用户已认证
  // ...
});

授权检查(IDOR预防)

// 用于用户特定资源
const requestedUserId = body.user_id;
const authenticatedUserId = user.id;

if (requestedUserId !== authenticatedUserId) {
  return new Response('Forbidden', { status: 403 });
}

角色检查(管理员)

// 检查管理员角色
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()
});

// 验证输入
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] 审计Edge Functions
    [TIMESTAMP] [supabase-audit-functions] [FINDING] P0: get-user-data中的IDOR
    [TIMESTAMP] [supabase-audit-functions] [CONTEXT_UPDATED] .sb-pentest-context.json已更新
    
  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": "以用户A身份,请求用户B的数据",
      "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": "任何认证用户可访问任何其他用户数据"
    }
  ],

  "remediation": "添加所有权检查: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": "普通用户访问管理员功能",
    "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": "任何认证用户具有管理员访问权限"
  }
}

相关技能

  • supabase-audit-rpc — 数据库函数(不同于Edge Functions)
  • supabase-audit-auth-config — 认证配置
  • supabase-report — 包含在最终报告中