mcpField
S
supabase-audit-rls

supabase-audit-rls

github.com/yoanbernabeuセキュリティ711.1k 回インストール39 週間前に更新
リポジトリ

supabase-audit-rls について

supabase-audit-rlsは、SupabaseのRow Level Security(RLS)ポリシーを確認するセキュリティ監査スキルです。アクセス制御や一般的な回避手法をテストし、発見事項、ログ、証拠を作業中に記録します。

主な機能

  1. 01RLSの有効化とポリシー設定の確認
  2. 02未認証アクセスとユーザー間アクセスのテスト
  3. 03フィルター、結合、RPCによる回避の確認
  4. 04影響の説明とSQL修正案の提示
  5. 05監査情報、ログ、証拠の逐次記録

活用シーン

  1. 01SupabaseプロジェクトのテーブルのRLS監査
  2. 02許可されたデータだけにアクセスできるか検証
  3. 03結合やRPCを介したアクセス回避の調査
  4. 04追跡可能なセキュリティ監査記録の作成

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/yoanbernabeu/supabase-pentest-skills --skill supabase-audit-rls

インストール後、Claude Code で/supabase-audit-rlsを入力して読み込まれたか確認します。

詳細

RLS ポリシー監査

🔴 重大:コンテキストファイルを段階的に更新する必要があります

コンテキストファイルには、最後にまとめてではなく、作業を進めながら書き込む必要があります。

  • 各発見事項の直後に、.sb-pentest-context.json に書き込んでください
  • 各テストの前後に、.sb-pentest-audit.log に記録してください
  • スキルの完了までファイルの更新を待たないでください
  • スキルがクラッシュまたは中断された場合でも、それまでのすべての発見事項がすでに保存されている必要があります

これは必須です。段階的な書き込みを怠ると、重大なエラーになります。

このスキルでは、一般的な脆弱性や設定ミスがないか、行レベルセキュリティ(RLS)ポリシーをテストします。

このスキルを使用するタイミング

  • テーブル内のデータ漏えいを発見した後
  • RLS ポリシーが正しく実装されていることを確認する場合
  • 一般的な RLS バイパス手法をテストする場合
  • 包括的なセキュリティ監査の一環として

前提条件

  • テーブルの一覧があること
  • Anon キーを利用できること
  • 可能であれば、認証済みユーザーのトークンでもテストすること

RLS を理解する

Supabase/PostgreSQL の行レベルセキュリティ:

-- Enable RLS on a table
ALTER TABLE posts ENABLE ROW LEVEL SECURITY;

-- Create a policy
CREATE POLICY "Users see own posts"
  ON posts FOR SELECT
  USING (auth.uid() = author_id);

RLS が有効でもポリシーが存在しない場合、すべてのアクセスがブロックされます。

一般的な RLS の問題

問題説明重大度
RLS が無効テーブルに RLS による保護がないP0
ポリシーの不足RLS は有効だが、SELECT ポリシーがないさまざま
過度に許可的ポリシーが過剰なアクセスを許可するP0-P1
操作の不足SELECT ポリシーはあるが、INSERT/UPDATE/DELETE ポリシーがないP1
USING と WITH CHECK読み取りは許可されるが、書き込みの制御に一貫性がないP1

テスト項目

このスキルでは、以下の一般的なバイパスシナリオをテストします。

1. 未認証アクセス
GET /rest/v1/users?select=*
# No Authorization header or with anon key only
2. ユーザー間のアクセス
# As user A, try to access user B's data
GET /rest/v1/orders?user_id=eq.[user-b-id]
Authorization: Bearer [user-a-token]
3. フィルターのバイパス
# Try to bypass filters with OR conditions
GET /rest/v1/posts?or=(published.eq.true,published.eq.false)
4. JOIN の悪用
# Try to access data through related tables
GET /rest/v1/comments?select=*,posts(*)
5. RPC のバイパス
# Check if RPC functions bypass RLS
POST /rest/v1/rpc/get_all_users

使用方法

基本的な RLS 監査
Audit RLS policies on my Supabase project
特定のテーブル
Test RLS on the users table
認証済みユーザーを使用
Test RLS policies using this user token: eyJ...

出力形式

═══════════════════════════════════════════════════════════
 RLS POLICY AUDIT
═══════════════════════════════════════════════════════════

 Project: abc123def.supabase.co
 Tables Audited: 8

 ─────────────────────────────────────────────────────────
 RLS Status by Table
 ─────────────────────────────────────────────────────────

 1. users
    RLS Enabled: ❌ NO
    Status: 🔴 P0 - NO RLS PROTECTION

    All operations allowed without restriction!
    Test Results:
    ├── Anon SELECT: ✓ Returns all 1,247 rows
    ├── Anon INSERT: ✓ Succeeds (tested with rollback)
    ├── Anon UPDATE: ✓ Would succeed
    └── Anon DELETE: ✓ Would succeed

    Immediate Fix:
    ```sql
    ALTER TABLE users ENABLE ROW LEVEL SECURITY;

    CREATE POLICY "Users see own data"
      ON users FOR ALL
      USING (auth.uid() = id);
    ```

 2. posts
    RLS Enabled: ✅ YES
    Policies Found: 2
    Status: ✅ PROPERLY CONFIGURED

    Policies:
    ├── "Public sees published" (SELECT)
    │   └── USING: (published = true)
    └── "Authors manage own" (ALL)
        └── USING: (auth.uid() = author_id)

    Test Results:
    ├── Anon SELECT: Only published posts (correct)
    ├── Anon INSERT: ❌ Blocked (correct)
    ├── Cross-user access: ❌ Blocked (correct)
    └── Filter bypass: ❌ Blocked (correct)

 3. orders
    RLS Enabled: ✅ YES
    Policies Found: 1
    Status: 🟠 P1 - PARTIAL ISSUE

    Policies:
    └── "Users see own orders" (SELECT)
        └── USING: (auth.uid() = user_id)

    Issue Found:
    ├── No INSERT policy - users can't create orders via API
    ├── No UPDATE policy - users can't modify their orders
    └── This may be intentional (orders via Edge Functions)

    Recommendation: Document if intentional, or add policies:
    ```sql
    CREATE POLICY "Users insert own orders"
      ON orders FOR INSERT
      WITH CHECK (auth.uid() = user_id);
    ```

 4. comments
    RLS Enabled: ✅ YES
    Policies Found: 2
    Status: 🟠 P1 - BYPASS POSSIBLE

    Policies:
    ├── "Anyone can read" (SELECT)
    │   └── USING: (true)  ← Too permissive
    └── "Users comment on posts" (INSERT)
        └── WITH CHECK: (auth.uid() = user_id)

    Issue Found:
    └── SELECT policy allows reading all comments
        including user_id, enabling user correlation

    Recommendation:
    ```sql
    -- Use a view to hide user_id
    CREATE VIEW public.comments_public AS
      SELECT id, post_id, content, created_at FROM comments;
    ```

 5. settings
    RLS Enabled: ❌ NO
    Status: 🔴 P0 - NO RLS PROTECTION

    Contains sensitive configuration!
    Immediate action required.

 ─────────────────────────────────────────────────────────
 Summary
 ─────────────────────────────────────────────────────────

 RLS Disabled: 2 tables (users, settings) ← CRITICAL
 RLS Enabled: 6 tables
   ├── Properly Configured: 3
   ├── Partial Issues: 2
   └── Major Issues: 1

 Bypass Tests:
 ├── Unauthenticated access: 2 tables vulnerable
 ├── Cross-user access: 0 tables vulnerable
 ├── Filter bypass: 0 tables vulnerable
 └── Join exploitation: 1 table allows data leakage

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

コンテキスト出力

{
  "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": "No RLS protection",
        "operations_exposed": ["SELECT", "INSERT", "UPDATE", "DELETE"]
      },
      {
        "table": "comments",
        "rls_enabled": true,
        "severity": "P1",
        "issue": "Overly permissive SELECT policy",
        "detail": "user_id exposed enabling correlation"
      }
    ]
  }
}

一般的な RLS パターン

良い例:ユーザーが自分のデータを所有する
CREATE POLICY "Users own their data"
  ON user_data FOR ALL
  USING (auth.uid() = user_id)
  WITH CHECK (auth.uid() = user_id);
良い例:公開読み取り、認証済みユーザーによる書き込み
-- Anyone can read
CREATE POLICY "Public read" ON posts
  FOR SELECT USING (published = true);

-- Only authors can write
CREATE POLICY "Author write" ON posts
  FOR INSERT WITH CHECK (auth.uid() = author_id);

CREATE POLICY "Author update" ON posts
  FOR UPDATE USING (auth.uid() = author_id);
悪い例:USING (true) の使用
-- ❌ Too permissive
CREATE POLICY "Anyone" ON secrets
  FOR SELECT USING (true);
悪い例:WITH CHECK の記述忘れ
-- ❌ Users can INSERT any user_id
CREATE POLICY "Insert" ON posts
  FOR INSERT WITH CHECK (true);  -- Should check 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 に記録します。

    [TIMESTAMP] [supabase-audit-rls] [START] Auditing RLS policies
    [TIMESTAMP] [supabase-audit-rls] [FINDING] P0: users table has no RLS
    [TIMESTAMP] [supabase-audit-rls] [CONTEXT_UPDATED] .sb-pentest-context.json updated
    
  3. ファイルが存在しない場合は、書き込みの前に作成します。

コンテキストファイルを更新しないことは許されません。

必須:証拠の収集

📁 証拠ディレクトリ: .sb-pentest-evidence/03-api-audit/rls-tests/

作成する証拠ファイル
ファイル内容
rls-tests/[table]-anon.json匿名アクセスのテスト結果
rls-tests/[table]-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": "Anonymous user SELECT access",
      "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": "VULNERABLE",
      "impact": "All user data accessible without authentication"
    },
    {
      "test_name": "anon_insert",
      "description": "Anonymous user INSERT access",
      "request": {
        "curl_command": "curl -X POST '$URL/rest/v1/users' -H 'apikey: $ANON_KEY' -d '{...}'"
      },
      "response": {
        "status": 201
      },
      "result": "VULNERABLE",
      "impact": "Can create arbitrary user records"
    }
  ],

  "remediation_sql": "ALTER TABLE users ENABLE ROW LEVEL SECURITY;\nCREATE POLICY \"Users see own data\" ON users FOR SELECT USING (auth.uid() = id);"
}
curl-commands.sh に追加
# === RLS BYPASS TESTS ===
# Test anon access to users table
curl -s "$SUPABASE_URL/rest/v1/users?select=*&limit=5" \
  -H "apikey: $ANON_KEY" -H "Authorization: Bearer $ANON_KEY"

# Test filter bypass
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 — セキュリティレポート全体

コメント