mcpField
S
supabase-audit-tables-read

supabase-audit-tables-read

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

supabase-audit-tables-read について

Supabase のテーブルデータへの読み取り権限を検査するセキュリティ監査スキルです。RLS の有効性やデータ露出を評価する監査担当者向けで、テーブルに読み取り専用クエリを実行し、データの機微性に応じて結果を評価します。

主な機能

  1. 01読み取り専用のテーブルアクセス検査
  2. 02クイック、サンプル、件数モード
  3. 03機微データの種類に応じた重大度評価
  4. 04テーブルごとの結果と監査ログの逐次保存
  5. 05アクセス証拠と curl の例の作成

活用シーン

  1. 01RLS が未認証の読み取りを防ぐか検証
  2. 02公開テーブルから実際に取得できるデータの確認
  3. 03行データを取得せずにアクセス可能な件数を把握

インストール

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

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

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

詳細

テーブルデータアクセスのテスト

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

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

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

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

このスキルは、公開されているテーブルからデータを読み取り、実際にどの情報へアクセスできるかを判定します。

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

  • テーブルの一覧表示後、実際にアクセスできるかを確認するとき
  • RLS ポリシーの有効性をテストするとき
  • データ漏えいの深刻度を評価するとき
  • 取得可能なデータを正確に記録するとき

前提条件

  • テーブルが一覧表示されていること(必要に応じて supabase-audit-tables-list が自動的に呼び出されます)
  • Anon キーが利用可能であること

仕組み

このスキルは、公開されている各テーブルに対して SELECT クエリを実行します。

GET https://[project].supabase.co/rest/v1/[table]?select=*&limit=5
Authorization: Bearer [anon-key]

重要: これは読み取り専用です。データの変更や削除は行いません。

テストモード

モード説明クエリ
Quick各テーブルの先頭 5 行?limit=5
Sampleテーブル全体からランダムにサンプルを取得?limit=10&order=random
Countデータを取得せず、行数のみを取得HEAD リクエスト

使用方法

基本的な読み取りテスト
Test read access on exposed tables
件数のみをすばやく確認
Count accessible rows in all tables (no data retrieval)
特定のテーブル
Test read access on the users table

出力形式

═══════════════════════════════════════════════════════════
 DATA ACCESS TEST RESULTS
═══════════════════════════════════════════════════════════

 Test Mode: Quick (5 rows per table)
 Tables Tested: 8

 ─────────────────────────────────────────────────────────
 Results by Table
 ─────────────────────────────────────────────────────────

 1. users
    Status: 🔴 P0 - DATA EXPOSED
    Rows Retrieved: 5 (of 1,247 total)
    Sample Data:
    ┌─────────────────────────────────────────────────────┐
    │ id: 550e8400-e29b-41d4-a716-446655440001           │
    │ email: [email protected] ← PII EXPOSED          │
    │ name: John Doe ← PII EXPOSED                       │
    │ avatar_url: https://...                            │
    │ created_at: 2025-01-15T10:30:00Z                   │
    └─────────────────────────────────────────────────────┘
    Finding: User emails and names accessible without auth

 2. profiles
    Status: 🟠 P1 - PARTIAL ACCESS
    Rows Retrieved: 5
    Note: Only public fields returned (RLS working partially)
    Columns Visible: id, bio, website
    Columns Blocked: user_id, social_links, private_notes

 3. posts
    Status: ✅ EXPECTED ACCESS
    Rows Retrieved: 5
    Note: Only published=true posts returned (RLS working)
    Data: Public content, appropriate access level

 4. orders
    Status: ✅ BLOCKED
    Response: 403 Forbidden
    Message: "new row violates row-level security policy"
    Note: RLS properly blocking access

 5. api_keys
    Status: ✅ BLOCKED
    Response: 403 Forbidden
    Note: RLS properly protecting secrets

 6. products
    Status: ✅ EXPECTED ACCESS
    Rows Retrieved: 5
    Note: Public catalog data, appropriate access

 7. comments
    Status: 🟠 P1 - MORE DATA THAN EXPECTED
    Rows Retrieved: 5
    Issue: user_id column exposed (can correlate to users)
    Recommendation: Use a view to hide user_id

 8. settings
    Status: 🔴 P0 - SENSITIVE DATA EXPOSED
    Rows Retrieved: 3
    Sample Data:
    ┌─────────────────────────────────────────────────────┐
    │ key: stripe_webhook_secret                          │
    │ value: whsec_xxxxxxxxxxxx ← SECRET EXPOSED         │
    └─────────────────────────────────────────────────────┘
    Finding: Application secrets in accessible table!

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

 P0 (Critical): 2 tables with sensitive data exposed
 P1 (High): 2 tables with partial/unexpected exposure
 Blocked: 2 tables properly protected
 Expected: 2 tables with appropriate public access

 Total Rows Accessible: 1,892 across exposed tables

 Immediate Actions:
 1. Fix 'settings' table - remove from public or add RLS
 2. Fix 'users' table - add RLS to protect email/name
 3. Review 'comments' to hide user correlation

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

重大度の評価

ステータス重大度基準
🔴 DATA EXPOSEDP0機密データ(PII、シークレット、財務情報)にアクセス可能
🟠 PARTIAL ACCESSP1想定より多くのデータにアクセス可能だが、重大ではない
🟡 UNEXPECTEDP2アクセス可能だが、リスクの低いデータ
✅ BLOCKED-RLS によってアクセスが適切に防止されている
✅ EXPECTED-公開データであり、アクセスは適切

データ分類

このスキルは、次の種類の機密データを識別します。

種類パターン公開された場合の重大度
PIIemail、phone、name、addressP0
財務情報amount、total、card、paymentP0
シークレットkey、secret、token、passwordP0
認証user_id、session、jwtP1
メタデータcreated_at、updated_atP2

コンテキスト出力

{
  "data_access": {
    "timestamp": "2025-01-31T10:30:00Z",
    "tables_tested": 8,
    "summary": {
      "p0_exposed": 2,
      "p1_partial": 2,
      "blocked": 2,
      "expected": 2
    },
    "results": [
      {
        "table": "users",
        "status": "exposed",
        "severity": "P0",
        "rows_accessible": 1247,
        "sensitive_columns": ["email", "name"],
        "sample_redacted": true
      },
      {
        "table": "settings",
        "status": "exposed",
        "severity": "P0",
        "rows_accessible": 3,
        "sensitive_data_types": ["secrets"],
        "finding": "Application secrets exposed"
      }
    ],
    "total_rows_accessible": 1892
  }
}

監査ログのエントリ

[2025-01-31T10:30:00Z] READ_TEST_START tables=8
[2025-01-31T10:30:01Z] READ_TEST table=users status=200 rows=5 severity=P0
[2025-01-31T10:30:01Z] READ_TEST table=orders status=403 severity=none
[2025-01-31T10:30:02Z] READ_TEST_COMPLETE exposed=4 blocked=2

修正例

ユーザーテーブルの場合
-- Enable RLS
ALTER TABLE users ENABLE ROW LEVEL SECURITY;

-- Only authenticated users see their own data
CREATE POLICY "Users see own data"
  ON users FOR SELECT
  USING (auth.uid() = id);

-- Or create a public view with limited columns
CREATE VIEW public.users_public AS
  SELECT id, avatar_url, created_at FROM users;
設定テーブルの場合
-- Remove from public access entirely
REVOKE ALL ON TABLE settings FROM anon, authenticated;

-- Access only via Edge Functions
-- In your Edge Function:
const { data } = await supabaseAdmin
  .from('settings')
  .select('*')
  .eq('key', 'stripe_webhook_secret')
  .single()
コンテンツテーブルの場合
-- RLS for published content only
CREATE POLICY "Public sees published posts"
  ON posts FOR SELECT
  USING (published = true);

-- Authors see their own drafts
CREATE POLICY "Authors see own posts"
  ON posts FOR SELECT
  USING (auth.uid() = author_id);

よくある問題

❌ 問題: すべてのテーブルが 403 を返す ✅ 解決策: RLS の制限が厳しすぎるか、Anon キーが無効である可能性があります。セキュリティの観点からは、実際には望ましい状態です。

❌ 問題: エラーはないのに結果が空 ✅ 解決策: RLS がすべての行をフィルタリングしています。テーブル構造にはアクセスできますが、データにはアクセスできません。

❌ 問題: 大きなテーブルでタイムアウトする ✅ 解決策: Count モードを使用するか、上限を減らしてください。

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

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

重要なルール:作業を進めながら書き込む

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

  1. 各テーブルのテスト前 → .sb-pentest-audit.log に操作を記録します
  2. 各テーブルのテスト後 → 結果を .sb-pentest-context.json に直ちに更新します
  3. 各調査結果の確認後 → .sb-pentest-audit.log に重大度を記録します

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

必須の操作(段階的に実施)
  1. 結果を含めて .sb-pentest-context.json を更新します。

    {
      "data_access": {
        "timestamp": "...",
        "tables_tested": 8,
        "summary": { "p0_exposed": 2, ... },
        "results": [ ... ],
        "total_rows_accessible": 1892
      }
    }
    
  2. .sb-pentest-audit.log に記録します。

    [TIMESTAMP] [supabase-audit-tables-read] [START] Testing data access
    [TIMESTAMP] [supabase-audit-tables-read] [FINDING] P0: users table exposed
    [TIMESTAMP] [supabase-audit-tables-read] [CONTEXT_UPDATED] .sb-pentest-context.json updated
    
  3. ファイルが存在しない場合は、書き込む前に作成します。

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

必須:証拠の収集

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

作成する証拠ファイル
ファイル内容
data-samples/[table]-sample.jsonアクセス可能な各テーブルのサンプルデータ
data-samples/[table]-blocked.jsonアクセスがブロックされた証拠(403 レスポンス)
証拠の形式(データが公開されている場合)
{
  "evidence_id": "API-READ-001",
  "timestamp": "2025-01-31T10:20:00Z",
  "category": "api-audit",
  "type": "data_access",
  "severity": "P0",
  "finding_id": "P0-002",

  "table": "users",

  "request": {
    "method": "GET",
    "url": "https://abc123def.supabase.co/rest/v1/users?select=*&limit=5",
    "headers": {
      "apikey": "[REDACTED]",
      "Authorization": "Bearer [REDACTED]"
    },
    "curl_command": "curl -s 'https://abc123def.supabase.co/rest/v1/users?select=*&limit=5' -H 'apikey: $ANON_KEY' -H 'Authorization: Bearer $ANON_KEY'"
  },

  "response": {
    "status": 200,
    "headers": {
      "content-range": "0-4/1247"
    },
    "total_rows": 1247,
    "sample_data": [
      {
        "id": "550e8400-e29b-41d4-...",
        "email": "[REDACTED]@example.com",
        "name": "[REDACTED]",
        "created_at": "2025-01-15T10:30:00Z"
      }
    ],
    "data_redacted": true
  },

  "analysis": {
    "severity": "P0",
    "pii_exposed": ["email", "name"],
    "total_records_accessible": 1247,
    "authentication_required": false
  }
}
証拠の形式(適切にブロックされている場合)
{
  "evidence_id": "API-READ-002",
  "timestamp": "2025-01-31T10:21:00Z",
  "table": "orders",
  "severity": null,

  "response": {
    "status": 403,
    "body": {"message": "new row violates row-level security policy"}
  },

  "analysis": {
    "rls_working": true,
    "access_blocked": true
  }
}
curl-commands.sh に追加
# === DATA ACCESS TESTS ===
# Test: Users table access
curl -s "$SUPABASE_URL/rest/v1/users?select=*&limit=5" \
  -H "apikey: $ANON_KEY" \
  -H "Authorization: Bearer $ANON_KEY"

# Test: Orders table access (should be blocked)
curl -s "$SUPABASE_URL/rest/v1/orders?select=*&limit=5" \
  -H "apikey: $ANON_KEY" \
  -H "Authorization: Bearer $ANON_KEY"

関連スキル

  • supabase-audit-tables-list — まずテーブルを一覧表示
  • supabase-audit-rls — RLS ポリシーを詳しく確認
  • supabase-report — 完全なレポートを生成

コメント