SupabaseRLS安全审计技能Skill supabase-audit-rls

这个技能用于测试Supabase项目中的行级安全(RLS)策略,识别常见漏洞和错误配置,帮助进行安全审计和漏洞修复。关键词:Supabase、RLS、安全审计、漏洞测试、数据库安全。

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

name: supabase-audit-rls description: 测试行级安全(RLS)策略以发现常见的绕过漏洞和错误配置。

RLS 策略审计

🔴 关键:需要渐进式文件更新

你必须在过程中写入上下文文件,而不仅仅在最后。

  • 在每次发现后立即写入.sb-pentest-context.json
  • 在每次测试前后记录到.sb-pentest-audit.log
  • 不要等到技能完成才更新文件
  • 如果技能崩溃或中断,所有先前的发现必须已经保存

这不是可选的。失败进行渐进式写入是一个关键错误。

这个技能测试行级安全(RLS)策略以发现常见漏洞和错误配置。

何时使用此技能

  • 在发现表中数据暴露后
  • 验证RLS策略是否正确实施
  • 测试常见的RLS绕过技术
  • 作为全面安全审计的一部分

先决条件

  • 列出表
  • 匿名密钥可用
  • 最好也使用认证用户令牌进行测试

理解RLS

Supabase/PostgreSQL中的行级安全:

-- 在表上启用RLS
ALTER TABLE posts ENABLE ROW LEVEL SECURITY;

-- 创建策略
CREATE POLICY "用户查看自己的帖子"
  ON posts FOR SELECT
  USING (auth.uid() = author_id);

如果RLS已启用但无策略存在,所有访问都被阻止。

常见RLS问题

问题 描述 严重性
RLS 禁用 表没有RLS保护 P0
缺失策略 RLS启用但无SELECT策略 可变
过于宽松 策略允许过多访问 P0-P1
缺失操作 有SELECT策略但无INSERT/UPDATE/DELETE P1
USING vs WITH CHECK 读取允许但写入不一致 P1

测试向量

此技能测试这些常见的绕过场景:

1. 未认证访问

GET /rest/v1/users?select=*
# 无Authorization头或仅使用匿名密钥

2. 跨用户访问

# 作为用户A,尝试访问用户B的数据
GET /rest/v1/orders?user_id=eq.[用户B-ID]
Authorization: Bearer [用户A令牌]

3. 过滤器绕过

# 尝试使用OR条件绕过过滤器
GET /rest/v1/posts?or=(published.eq.true,published.eq.false)

4. 连接利用

# 尝试通过相关表访问数据
GET /rest/v1/comments?select=*,posts(*)

5. RPC绕过

# 检查RPC函数是否绕过RLS
POST /rest/v1/rpc/get_all_users

用法

基本RLS审计

审计我的Supabase项目上的RLS策略

特定表

测试users表上的RLS

使用认证用户

使用此用户令牌测试RLS策略: eyJ...

输出格式

═══════════════════════════════════════════════════════════
 RLS 策略审计
═══════════════════════════════════════════════════════════

 项目: abc123def.supabase.co
 审计表数: 8

 ─────────────────────────────────────────────────────────
 按表的RLS状态
 ─────────────────────────────────────────────────────────

 1. users
    RLS 启用: ❌ 否
    状态: 🔴 P0 - 无RLS保护

    所有操作无限制允许!
    测试结果:
    ├── 匿名SELECT: ✓ 返回所有1,247行
    ├── 匿名INSERT: ✓ 成功(测试后回滚)
    ├── 匿名UPDATE: ✓ 将成功
    └── 匿名DELETE: ✓ 将成功

    立即修复:
    ```sql
    ALTER TABLE users ENABLE ROW LEVEL SECURITY;

    CREATE POLICY "用户查看自己的数据"
      ON users FOR ALL
      USING (auth.uid() = id);
    ```

 2. posts
    RLS 启用: ✅ 是
    找到策略: 2
    状态: ✅ 正确配置

    策略:
    ├── "公开查看已发布" (SELECT)
    │   └── USING: (published = true)
    └── "作者管理自己的" (ALL)
        └── USING: (auth.uid() = author_id)

    测试结果:
    ├── 匿名SELECT: 仅已发布帖子(正确)
    ├── 匿名INSERT: ❌ 阻止(正确)
    ├── 跨用户访问: ❌ 阻止(正确)
    └── 过滤器绕过: ❌ 阻止(正确)

 3. orders
    RLS 启用: ✅ 是
    找到策略: 1
    状态: 🟠 P1 - 部分问题

    策略:
    └── "用户查看自己的订单" (SELECT)
        └── USING: (auth.uid() = user_id)

    发现问题:
    ├── 无INSERT策略 - 用户无法通过API创建订单
    ├── 无UPDATE策略 - 用户无法修改其订单
    └── 这可能是故意的(通过Edge Functions处理订单)

    建议: 如果故意,请记录,或添加策略:
    ```sql
    CREATE POLICY "用户插入自己的订单"
      ON orders FOR INSERT
      WITH CHECK (auth.uid() = user_id);
    ```

 4. comments
    RLS 启用: ✅ 是
    找到策略: 2
    状态: 🟠 P1 - 可能绕过

    策略:
    ├── "任何人都可以读取" (SELECT)
    │   └── USING: (true)  ← 过于宽松
    └── "用户在帖子上评论" (INSERT)
        └── WITH CHECK: (auth.uid() = user_id)

    发现问题:
    └── SELECT策略允许读取所有评论
        包括user_id,使用户关联成为可能

    建议:
    ```sql
    -- 使用视图隐藏user_id
    CREATE VIEW public.comments_public AS
      SELECT id, post_id, content, created_at FROM comments;
    ```

 5. settings
    RLS 启用: ❌ 否
    状态: 🔴 P0 - 无RLS保护

    包含敏感配置!
    需要立即行动。

 ─────────────────────────────────────────────────────────
 摘要
 ─────────────────────────────────────────────────────────

 RLS 禁用: 2 表 (users, settings) ← 关键
 RLS 启用: 6 表
   ├── 正确配置: 3
   ├── 部分问题: 2
   └── 主要问题: 1

 绕过测试:
 ├── 未认证访问: 2 表易受攻击
 ├── 跨用户访问: 0 表易受攻击
 ├── 过滤器绕过: 0 表易受攻击
 └── 连接利用: 1 表允许数据泄漏

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

上下文输出

{
  "rls_audit": {
    "timestamp": "2025-01-31T10:45:00Z",
    "tables_audited": 8,
    "summary": {
      "rls_disabled": 2,
      "rls_enabled": 6,
      "properly_configured": 3,
      "partial_issues": 2,
      "major_issues": 1
    },
    "findings": [
      {
        "table": "users",
        "rls_enabled": false,
        "severity": "P0",
        "issue": "无RLS保护",
        "operations_exposed": ["SELECT", "INSERT", "UPDATE", "DELETE"]
      },
      {
        "table": "comments",
        "rls_enabled": true,
        "severity": "P1",
        "issue": "SELECT策略过于宽松",
        "detail": "user_id暴露,使用户关联成为可能"
      }
    ]
  }
}

常见RLS模式

好: 用户拥有自己的数据

CREATE POLICY "用户拥有自己的数据"
  ON user_data FOR ALL
  USING (auth.uid() = user_id)
  WITH CHECK (auth.uid() = user_id);

好: 公开读取,认证写入

-- 任何人都可以读取
CREATE POLICY "公开读取" ON posts
  FOR SELECT USING (published = true);

-- 仅作者可以写入
CREATE POLICY "作者写入" ON posts
  FOR INSERT WITH CHECK (auth.uid() = author_id);

CREATE POLICY "作者更新" ON posts
  FOR UPDATE USING (auth.uid() = author_id);

坏: 使用 (true)

-- ❌ 过于宽松
CREATE POLICY "任何人" ON secrets
  FOR SELECT USING (true);

坏: 忘记 WITH CHECK

-- ❌ 用户可以INSERT任何user_id
CREATE POLICY "插入" ON posts
  FOR INSERT WITH CHECK (true);  -- 应该检查user_id!

RLS 绕过文档

对于每个发现的绕过,技能提供:

  1. 漏洞描述
  2. 概念证明查询
  3. 影响评估
  4. 修复SQL代码
  5. 文档链接

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

⚠️ 此技能必须在执行过程中渐进式更新跟踪文件,而不仅仅在最后。

关键规则: 边走边写

不要将所有写入批处理到最后。相反:

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

这确保如果技能中断、崩溃或超时,所有到该点的发现都被保存。

所需操作(渐进式)

  1. 更新.sb-pentest-context.json 与结果:

    {
      "rls_audit": {
        "timestamp": "...",
        "tables_audited": 8,
        "summary": { "rls_disabled": 2, ... },
        "findings": [ ... ]
      }
    }
    
  2. 记录到.sb-pentest-audit.log:

    [时间戳] [supabase-audit-rls] [开始] 审计RLS策略
    [时间戳] [supabase-audit-rls] [发现] P0: users表无RLS
    [时间戳] [supabase-audit-rls] [上下文已更新] .sb-pentest-context.json已更新
    
  3. 如果文件不存在,在写入前创建它们。

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

强制: 证据收集

📁 证据目录: .sb-pentest-evidence/03-api-audit/rls-tests/

要创建的证据文件

文件 内容
rls-tests/[表]-anon.json 匿名访问测试结果
rls-tests/[表]-auth.json 认证访问测试结果
rls-tests/cross-user-test.json 跨用户访问尝试

证据格式(RLS绕过)

{
  "evidence_id": "RLS-001",
  "timestamp": "2025-01-31T10:25:00Z",
  "category": "api-audit",
  "type": "rls_test",
  "severity": "P0",

  "table": "users",
  "rls_enabled": false,

  "tests": [
    {
      "test_name": "anon_select",
      "description": "匿名用户SELECT访问",
      "request": {
        "curl_command": "curl -s '$URL/rest/v1/users?select=*&limit=5' -H 'apikey: $ANON_KEY'"
      },
      "response": {
        "status": 200,
        "rows_returned": 5,
        "total_accessible": 1247
      },
      "result": "易受攻击",
      "impact": "所有用户数据无需认证即可访问"
    },
    {
      "test_name": "anon_insert",
      "description": "匿名用户INSERT访问",
      "request": {
        "curl_command": "curl -X POST '$URL/rest/v1/users' -H 'apikey: $ANON_KEY' -d '{...}'"
      },
      "response": {
        "status": 201
      },
      "result": "易受攻击",
      "impact": "可以创建任意用户记录"
    }
  ],

  "remediation_sql": "ALTER TABLE users ENABLE ROW LEVEL SECURITY;
CREATE POLICY \"用户查看自己的数据\" ON users FOR SELECT USING (auth.uid() = id);"
}

添加到 curl-commands.sh

# === RLS 绕过测试 ===
# 测试对users表的匿名访问
curl -s "$SUPABASE_URL/rest/v1/users?select=*&limit=5" \
  -H "apikey: $ANON_KEY" -H "Authorization: Bearer $ANON_KEY"

# 测试过滤器绕过
curl -s "$SUPABASE_URL/rest/v1/posts?or=(published.eq.true,published.eq.false)" \
  -H "apikey: $ANON_KEY"

相关技能

  • supabase-audit-tables-list — 首先列出表
  • supabase-audit-tables-read — 查看实际数据暴露
  • supabase-audit-rpc — RPC函数可能绕过RLS
  • supabase-report — 完整安全报告