mcpField
S
supabase-audit-authenticated

supabase-audit-authenticated

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

supabase-audit-authenticated について

認証ユーザーとして Supabase のアクセスを検査するセキュリティ監査スキルです。テストユーザーを作成し、認証時と匿名時のアクセスを比較して、IDOR、他ユーザーのデータ閲覧、権限昇格を調べます。実行には明示的な同意が必要です。

主な機能

  1. 01同意に基づくテストユーザー作成
  2. 02認証時と匿名時のアクセス比較
  3. 03IDOR と他ユーザーへのアクセス検査
  4. 04Storage と Realtime のアクセス検査
  5. 05監査ログと証拠の逐次保存

活用シーン

  1. 01RLS が自分のデータだけを許可するか確認
  2. 02Supabase のテーブルで IDOR を調査
  3. 03認証時と匿名時のアクセス結果を比較

インストール

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

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

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

詳細

認証済みユーザーの監査

🔴 重大:ファイルを段階的に更新する必要があります

コンテキストファイルには、最後だけではなく、作業を進めながら必ず書き込んでください。

  • テストを実施するたびに、直ちに .sb-pentest-context.json に書き込んでください
  • 各アクションの前後に .sb-pentest-audit.log に記録してください
  • スキルの完了までファイルの更新を待ってはいけません
  • スキルがクラッシュまたは中断された場合でも、それまでの調査結果がすべて保存されている必要があります

これは任意ではありません。段階的に書き込まないことは重大なエラーです。

このスキルでは、明示的な許可を得てテストユーザーを作成し、認証済みの場合と匿名の場合のアクセスを比較して、IDOR 脆弱性を検出します。

⚠️ 重要:ユーザーの同意が必要です

╔═══════════════════════════════════════════════════════════════════╗
║  🔐 USER CREATION CONSENT REQUIRED                                ║
╠═══════════════════════════════════════════════════════════════════╣
║                                                                   ║
║  This skill will CREATE A TEST USER in your Supabase project.     ║
║                                                                   ║
║  The user will be created with:                                   ║
║  • Email: pentest-[random]@security-audit.local                   ║
║  • Password: Strong random password (32+ chars)                   ║
║  • Purpose: Testing authenticated access vs anonymous             ║
║                                                                   ║
║  At the end of the audit, you will be asked if you want to        ║
║  DELETE the test user (recommended).                              ║
║                                                                   ║
║  Do you authorize the creation of a test user?                    ║
║  Type "yes, create test user" to proceed.                         ║
║                                                                   ║
╚═══════════════════════════════════════════════════════════════════╝

ユーザーの明示的な同意なしに進めてはいけません。

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

  • 匿名アクセスのテストを完了した後
  • IDOR(安全でない直接オブジェクト参照)脆弱性を検出する場合
  • ユーザー間のデータアクセスをテストする場合
  • 認証済みユーザーに対して RLS ポリシーが機能することを検証する場合
  • 権限昇格の問題を見つける場合

前提条件

  • サインアップが可能であること(または招待フローを使用すること)
  • Anon キーが利用可能であること
  • 匿名アクセスの監査が完了していること(推奨)

認証済みテストが重要な理由

多くの脆弱性は、認証後にのみ現れます。

脆弱性匿名認証済み
RLS のバイパス(RLS なし)✓ 検出可能✓ 検出可能
IDOR✗ 確認不可✓ 認証時のみ確認可能
ユーザー間アクセス✗ 確認不可✓ 認証時のみ確認可能
権限昇格✗ 確認不可✓ 認証時のみ確認可能
過度に許容的な RLS一部✓ 完全に検出可能

テストユーザーの作成

メールアドレス形式
pentest-[8-char-random]@security-audit.local

例:[email protected]

パスワードの生成

以下を満たす強力なパスワードを使用します。

  • 32 文字以上
  • 大文字、小文字、数字、記号を含む
  • 暗号論的にランダム

例:Xk9$mP2#vL5@nQ8&jR4*wY7!hT3%bU6^

パスワードは一度だけ表示され、証跡に保存されます。

実施するテスト

1. ユーザーの作成とログイン
# Create user
curl -X POST "$SUPABASE_URL/auth/v1/signup" \
  -H "apikey: $ANON_KEY" \
  -H "Content-Type: application/json" \
  -d '{"email": "[email protected]", "password": "[STRONG_PASSWORD]"}'

# Login and get JWT
curl -X POST "$SUPABASE_URL/auth/v1/token?grant_type=password" \
  -H "apikey: $ANON_KEY" \
  -H "Content-Type: application/json" \
  -d '{"email": "[email protected]", "password": "[STRONG_PASSWORD]"}'
2. 認証済みと匿名の比較

各テーブルについて、次のテストを実施します。

テスト匿名認証済み検出結果
SELECT0 行1,247 行🔴 認証時のみデータが露出
自分のデータ該当なし自分の行のみ✅ RLS が機能
他のユーザーのデータ該当なしすべての行🔴 ユーザー間アクセス
3. IDOR テスト
# As test user, try to access other user's data
curl "$SUPABASE_URL/rest/v1/orders?user_id=eq.[OTHER_USER_ID]" \
  -H "apikey: $ANON_KEY" \
  -H "Authorization: Bearer [TEST_USER_JWT]"

# If returns data: IDOR vulnerability!
4. ユーザー間アクセス
# Get test user's ID from JWT
TEST_USER_ID=$(echo $JWT | jq -r '.sub')

# Try to access data belonging to a different user
curl "$SUPABASE_URL/rest/v1/profiles?id=neq.$TEST_USER_ID" \
  -H "Authorization: Bearer [TEST_USER_JWT]"

# If returns other users' profiles: Cross-user access!
5. 認証済みでのストレージ
# Test authenticated storage access
curl "$SUPABASE_URL/storage/v1/object/list/documents" \
  -H "apikey: $ANON_KEY" \
  -H "Authorization: Bearer [TEST_USER_JWT]"

# Compare with anonymous results
6. 認証済みでのリアルタイム
// Subscribe to table changes as authenticated user
const channel = supabase.channel('test')
  .on('postgres_changes', {
    event: '*',
    schema: 'public',
    table: 'orders'
  }, payload => console.log(payload))
  .subscribe()

// Does it receive OTHER users' order changes?

出力形式

═══════════════════════════════════════════════════════════
 AUTHENTICATED USER AUDIT
═══════════════════════════════════════════════════════════

 ─────────────────────────────────────────────────────────
 Test User Creation
 ─────────────────────────────────────────────────────────

 Status: ✅ User created successfully

 Test User Details:
 ├── Email: [email protected]
 ├── User ID: 550e8400-e29b-41d4-a716-446655440099
 ├── Password: [Saved to evidence - shown once]
 └── JWT obtained: ✅

 ─────────────────────────────────────────────────────────
 Anonymous vs Authenticated Comparison
 ─────────────────────────────────────────────────────────

 Table: users
 ├── Anonymous access: 0 rows
 ├── Authenticated access: 1,247 rows ← ALL USERS!
 └── Status: 🔴 P0 - Data hidden from anon but exposed to any auth user

 Table: orders
 ├── Anonymous access: 0 rows (blocked)
 ├── Authenticated access: 1 row (own orders only)
 └── Status: ✅ RLS working correctly

 Table: profiles
 ├── Anonymous access: 0 rows
 ├── Authenticated access: 1,247 rows ← ALL PROFILES!
 ├── Own profile only expected: ❌ NO
 └── Status: 🔴 P0 - Cross-user profile access

 ─────────────────────────────────────────────────────────
 IDOR Testing
 ─────────────────────────────────────────────────────────

 Test: Access other user's orders by ID
 ├── Request: GET /orders?user_id=eq.[other-user-id]
 ├── Auth: Test user JWT
 ├── Response: 200 OK - 15 orders returned
 └── Status: 🔴 P0 - IDOR VULNERABILITY

 Proof:
 curl "$URL/rest/v1/orders?user_id=eq.other-user-uuid" \
   -H "Authorization: Bearer [test-user-jwt]"
 # Returns orders belonging to other-user-uuid!

 Test: Access admin endpoints
 ├── Request: GET /functions/v1/admin-panel
 ├── Auth: Test user JWT (regular user)
 ├── Response: 200 OK - Admin data returned!
 └── Status: 🔴 P0 - PRIVILEGE ESCALATION

 ─────────────────────────────────────────────────────────
 Storage with Authentication
 ─────────────────────────────────────────────────────────

 Bucket: documents
 ├── Anonymous: ❌ 0 files (blocked)
 ├── Authenticated: ✅ 523 files visible ← ALL USERS' FILES!
 └── Status: 🔴 P1 - Auth users see all documents

 Bucket: user-uploads
 ├── Anonymous: ❌ 0 files
 ├── Authenticated: 3 files (own files only)
 └── Status: ✅ RLS working correctly

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

 New Findings (Auth-only):
 ├── 🔴 P0: users table - all users visible to any auth user
 ├── 🔴 P0: profiles table - cross-user access
 ├── 🔴 P0: IDOR in orders - can access any user's orders
 ├── 🔴 P0: Privilege escalation in admin-panel
 └── 🟠 P1: documents bucket - all files visible to auth users

 Comparison:
 ├── Issues found (Anonymous): 3
 ├── Issues found (Authenticated): 8 ← 5 NEW ISSUES!
 └── Auth-only vulnerabilities: 5

 Recommendation:
 These issues were NOT visible in anonymous testing!
 Always test with authenticated users.

 ─────────────────────────────────────────────────────────
 Cleanup
 ─────────────────────────────────────────────────────────

 ⚠️  Test user still exists in database.

 Do you want to delete the test user?
 Email: [email protected]

 [This requires service_role key or manual deletion]

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

コンテキスト出力

{
  "authenticated_audit": {
    "timestamp": "2025-01-31T12:00:00Z",
    "test_user": {
      "email": "[email protected]",
      "user_id": "550e8400-e29b-41d4-a716-446655440099",
      "created_at": "2025-01-31T12:00:00Z",
      "deleted": false
    },
    "comparison": {
      "tables": {
        "users": {
          "anon_access": 0,
          "auth_access": 1247,
          "expected_auth_access": "own_row_only",
          "severity": "P0",
          "finding": "All users visible to any authenticated user"
        },
        "orders": {
          "anon_access": 0,
          "auth_access": 1,
          "expected_auth_access": "own_rows_only",
          "severity": null,
          "finding": "RLS working correctly"
        }
      },
      "idor_tests": [
        {
          "test": "access_other_user_orders",
          "vulnerable": true,
          "severity": "P0",
          "proof": "curl command..."
        }
      ],
      "privilege_escalation": [
        {
          "endpoint": "/functions/v1/admin-panel",
          "vulnerable": true,
          "severity": "P0"
        }
      ]
    },
    "summary": {
      "anon_issues": 3,
      "auth_issues": 8,
      "auth_only_issues": 5
    }
  }
}

RLS ポリシーの例

正しい例:ユーザーが自分のデータのみを表示する
-- This RLS policy is correct
CREATE POLICY "Users see own data"
  ON users FOR SELECT
  USING (auth.uid() = id);

-- Result:
-- Anonymous: 0 rows
-- Authenticated: 1 row (own data)
誤った例:すべての認証済みユーザーがすべてのデータを表示できる
-- This RLS policy is WRONG
CREATE POLICY "Authenticated users see all"
  ON users FOR SELECT
  USING (auth.role() = 'authenticated');  -- ❌ Too permissive!

-- Result:
-- Anonymous: 0 rows
-- Authenticated: ALL rows ← VULNERABILITY!
正しい修正:
-- Fix: Add user ownership check
CREATE POLICY "Users see own data"
  ON users FOR SELECT
  USING (auth.uid() = id);  -- ✅ Only own row

クリーンアップの方法

方法 1:手動で削除する(ダッシュボード)
Supabase Dashboard → Authentication → Users → Find test user → Delete
方法 2:service_role キーを使用する(利用可能な場合)
curl -X DELETE "$SUPABASE_URL/auth/v1/admin/users/[USER_ID]" \
  -H "apikey: $SERVICE_ROLE_KEY" \
  -H "Authorization: Bearer $SERVICE_ROLE_KEY"
方法 3:後で対応する

テストユーザーには機能しないメールドメイン(security-audit.local)を使用しているため、悪用することはできません。

必須:証跡の収集

📁 証跡ディレクトリ: .sb-pentest-evidence/05-auth-audit/authenticated-tests/

作成する証跡ファイル
ファイル内容
test-user-created.jsonテストユーザーの詳細(パスワードを安全に保存)
anon-vs-auth-comparison.json匿名と認証済みの比較
idor-tests/[table].jsonIDOR テストの結果
privilege-escalation.json権限昇格テスト
証跡の形式
{
  "evidence_id": "AUTH-TEST-001",
  "timestamp": "2025-01-31T12:00:00Z",
  "category": "auth-audit",
  "type": "authenticated_testing",

  "test_user": {
    "email": "[email protected]",
    "user_id": "550e8400-...",
    "password": "[STORED SECURELY - DO NOT COMMIT]"
  },

  "comparison_test": {
    "table": "users",
    "anonymous": {
      "curl_command": "curl '$URL/rest/v1/users' -H 'apikey: $ANON_KEY'",
      "response_status": 200,
      "rows_returned": 0
    },
    "authenticated": {
      "curl_command": "curl '$URL/rest/v1/users' -H 'apikey: $ANON_KEY' -H 'Authorization: Bearer $JWT'",
      "response_status": 200,
      "rows_returned": 1247
    },
    "finding": {
      "severity": "P0",
      "issue": "All users visible to any authenticated user",
      "expected": "Only own row should be visible",
      "impact": "Full user enumeration for any authenticated user"
    }
  }
}
curl-commands.sh に追加
# === AUTHENTICATED TESTING ===
# NOTE: Replace [JWT] with test user's JWT

# Compare anonymous vs authenticated access
curl -s "$SUPABASE_URL/rest/v1/users?select=*&limit=5" -H "apikey: $ANON_KEY"
curl -s "$SUPABASE_URL/rest/v1/users?select=*&limit=5" -H "apikey: $ANON_KEY" -H "Authorization: Bearer [JWT]"

# IDOR test - access other user's data
curl -s "$SUPABASE_URL/rest/v1/orders?user_id=eq.[OTHER_USER_ID]" \
  -H "apikey: $ANON_KEY" \
  -H "Authorization: Bearer [JWT]"

# Cross-user profile access
curl -s "$SUPABASE_URL/rest/v1/profiles?id=neq.[TEST_USER_ID]" \
  -H "apikey: $ANON_KEY" \
  -H "Authorization: Bearer [JWT]"

必須:コンテキストファイルの段階的な更新

⚠️ このスキルでは、実行中に追跡ファイルを段階的に更新する必要があります。最後にまとめて更新してはいけません。

重要なルール:作業中に書き込む

最後にまとめてすべてを書き込まないでください。 代わりに、次の手順に従ってください。

  1. ユーザー作成前 → 同意と操作を .sb-pentest-audit.log に記録します
  2. ユーザー作成後 → ユーザーの詳細を直ちにコンテキストと証拠に保存します
  3. 各比較テストの後 → 結果を .sb-pentest-context.json に更新します
  4. 各 IDOR テストの後 → 証拠を直ちに保存します

これにより、スキルが中断されたり、クラッシュしたり、タイムアウトしたりしても、その時点までのすべての調査結果が保持されます。

必須アクション(段階的に実行)
  1. ユーザー作成を記録する:

    [TIMESTAMP] [supabase-audit-authenticated] [CONSENT] User authorized test user creation
    [TIMESTAMP] [supabase-audit-authenticated] [CREATED] Test user [email protected]
    
  2. テストユーザーを直ちにコンテキストに保存する:

    {
      "authenticated_audit": {
        "test_user": {
          "email": "...",
          "user_id": "...",
          "created_at": "..."
        }
      }
    }
    
  3. 調査結果が判明するたびに記録する:

    [TIMESTAMP] [supabase-audit-authenticated] [FINDING] P0: IDOR in orders table
    

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

関連スキル

  • supabase-audit-auth-signup — まずサインアップが開放されているかテストします
  • supabase-audit-tables-read — 匿名ユーザーの結果と比較します
  • supabase-audit-rls — RLS ポリシーを詳しく調査します
  • supabase-audit-functions — 認証済みユーザーで関数へのアクセスをテストします
  • supabase-report — 認証済みユーザーのみが確認できる調査結果をレポートに含めます

コメント