FixVibe

// docs / baas security / firebase rules scanner

Firebase ルールスキャナ: 開いている Firestore、Realtime Database、Storage ルールを検出

Firebase アプリは一貫した方法でセキュリティに失敗します: テストモードのクイックスタートから残された <code>allow read, write: if true;</code> ルールが、本番前に置き換えられないまま放置されるのです。AI コーディングツールはこれらのルールをドキュメント例から逐語的に生成し、開発者にハードニングを促すことはほとんどありません。本記事では、Firebase ルールスキャナがプロジェクトの外側から Firestore、Realtime Database、Cloud Storage 全体で開いたルールをどう検出するか、そして検出された内容をどう修正するかを示します。

スキャナが開いた Firebase ルールを見つける仕組み

Firebase サービスは、よく知られた予測可能な URL 形状を公開します。資格情報を持たないスキャナは、各サービスを探り、匿名読み取りが成功するかを観察できます。FixVibe の baas.firebase-rules チェックは、Firebase サービスごとに 1 つずつ、3 つの独立したプローブを実行します:

  • <strong>Firestore.</strong> The scanner extracts the project ID from the deployed app's bundle (it's in <code>firebase.initializeApp({ projectId: ... })</code>), then issues <code>GET https://firestore.googleapis.com/v1/projects/[project-id]/databases/(default)/documents/[collection]:listDocuments</code> against common collection names. A <code>200 OK</code> with documents in the response means <code>allow read</code> is permissive.
  • Realtime Database。 スキャナは https://[project-id]-default-rtdb.firebaseio.com/.json を探ります。ルートが匿名で読めるなら、レスポンスはデータベースツリー全体の JSON です。より保守的なテストでは .json?shallow=true をクエリし、これはトップレベルキーのみを返します — どちらも検出対象です。
  • Cloud Storage。 スキャナは https://firebasestorage.googleapis.com/v0/b/[project-id].appspot.com/o をクエリします。レスポンスが認証なしでファイル名を一覧表示する場合、バケットは匿名で列挙可能です。個々のファイルダウンロードが拒否されていても、列挙可能なストレージは検出対象です — 攻撃者はバケットを列挙して推測可能なファイル名を見つけます。

テストモードの落とし穴の実際の姿

Firebase のクイックスタートドキュメントには、インターネット上で最もコピーされているルールブロックの 1 つが含まれています:

firebase
rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if true;
    }
  }
}

Firebase はかつてこれらのルールに 30 日間の自動期限を追加していました。それは変わりました: 今日では、開発者がそれらを置き換えない限り、ルールは永遠に持続します。AI コーディングツールは — テストモードブロックを含む数年分のドキュメントで訓練されているため — それを逐語的に発し、開発者に「これがあなたのセキュリティルールです」と伝えることがよくあります。そうではありません。

本番に現れるが同様に許容的な他のバリアント:

firebase
// future-date variant — equivalent to "if true"
allow read, write: if request.time < timestamp.date(2099, 1, 1);

// authenticated-user variant — any signed-in user reads and writes anything
allow read: if true;
allow write: if request.auth != null;

// any-auth variant — any signed-in user owns every document
allow read, write: if request.auth != null;
  • 未来のタイムスタンプバリアント: 遠い未来の日付まですべてを許可するルール。事実上期限切れにならない (上のハイライトされたブロックを参照)。
  • allow read: if true; allow write: if request.auth != null; — 公開読み取り、認証済みユーザーは誰でも書き込み可能。
  • allow read, write: if request.auth != null; — サインインしたユーザーは誰でも、他のユーザーのデータを含む任意のドキュメントを読み書き可能。

スキャナが開いたルールを見つけたときの対応

開いた Firebase ルールはランタイムの緊急事態です。修正の形は 3 つのサービスすべてで同じです: すべてのルールを request.auth.uid でスコープし、明示的な所有者フィールドと照合します。各サービスにはそれぞれのルール構文があります:

Firestore

match /users/{userId} { allow read, write: if request.auth != null && request.auth.uid == userId; }。パスセグメントバインディング {userId} がユーザーが触れることのできる唯一のドキュメントになります。

firebase
match /users/{userId} {
  allow read, write: if request.auth != null
                     && request.auth.uid == userId;
}

Realtime Database

<code>{ "rules": { "users": { "$uid": { ".read": "$uid === auth.uid", ".write": "$uid === auth.uid" } } } }</code>. The <code>$uid</code> wildcard captures the path segment for comparison.

json
{
  "rules": {
    "users": {
      "$uid": {
        ".read":  "$uid === auth.uid",
        ".write": "$uid === auth.uid"
      }
    }
  }
}

Cloud Storage

service firebase.storage { match /b/{bucket}/o { match /users/{userId}/{allPaths=**} { allow read, write: if request.auth.uid == userId; } } }。慣例: ファイルを users/[uid]/[filename] 配下に保存し、パスで所有権を強制します。

firebase
service firebase.storage {
  match /b/{bucket}/o {
    match /users/{userId}/{allPaths=**} {
      allow read, write: if request.auth.uid == userId;
    }
  }
}

Firebase CLI でルールをデプロイ: firebase deploy --only firestore:rulesfirebase deploy --only databasefirebase deploy --only storage。FixVibe スキャンを再実行して新しいルールが本番に反映されていることを検証します — baas.firebase-rules の検出結果はクリアされるはずです。

bash
firebase deploy --only firestore:rules
firebase deploy --only database
firebase deploy --only storage

Firebase 組み込みツールとの比較

Firebase コンソールは現在のルールを表示しますが、ランタイムの挙動と照らし合わせて監査することはありません。Firebase ルールシミュレータは合成リクエストに対してルールロジックをテストさせてくれます — 有用ですがローカルです。どちらのツールも、公開インターネット上の匿名攻撃者にあなたの本番ルールが実際に何を返すかは教えてくれません。 FixVibe のような外部スキャナ (または手動構成された Burp Suite) だけが、攻撃者と同じ角度から探ります。Google 自身の App Check は悪用を緩和しますが、正しくスコープされたルールの代わりにはなりません。

よくある質問

スキャナは私の Firestore データを読んだり変更したりしますか?

パッシブスキャンは、ルールが許可するかを確認するために、サービスごとに最大 1 回の匿名読み取りを発行します。スキャナはレスポンス形状とデータの存在を記録するだけで、ページングしたり、ドキュメントを列挙したり、書き込んだりはしません。書き込みプローブは検証済みドメイン所有権の背後でゲートされ、未検証のターゲットに対しては実行されません。

私の Firebase プロジェクトが App Check を使用している場合はどうなりますか?

App Check は未認証リクエストを 403 で拒否します。App Check トークンを持たないスキャナはすべてのプローブで 403 を見ます — それが正しい結果です。App Check はルール正確性の代替ではない (盗まれた App Check トークンと開いたルールの組み合わせは依然としてデータを漏洩します) が、機会主義的な外部スキャンをブロックします。

スキャナは部分的なルール設定ミス (読み取りは開、書き込みは閉) を検出できますか?

はい — 各ルール (allow readallow write) は別々に探られます。200 OK で成功する読み取り専用プローブは、書き込みが拒否されていても読み取り開検出を報告します。これら 2 つの検出は別物です: データ流出とデータ操作は別のリスクです。

カスタムドメインでデプロイされた Firebase アプリでも動作しますか?

はい。スキャナはドメインではなくデプロイされたバンドルから Firebase プロジェクト ID を抽出します。カスタムドメイン、app.web.app サブドメイン、セルフホストされた Firebase アプリは、JavaScript バンドルが到達可能である限り、同じように動作します。

次のステップ

本番 URL に対して無料の FixVibe スキャンを実行してください — baas.firebase-rules チェックはすべてのプランで提供され、Firestore、Realtime Database、Cloud Storage 全体で開いたルールをフラグします。allow read, write: if true パターン専用のより深い解説についてはFirebase の allow read, write: if true の解説を参照してください。Supabase、Firebase、Clerk、Auth0 にわたる全体像についてはBaaS 設定ミススキャナをお読みください。

// baas サーフェスをスキャン

他の誰かよりも先に、開いているテーブルを見つけてください。

本番 URL を入力してください。FixVibe はあなたのアプリが通信する BaaS プロバイダを列挙し、公開エンドポイントを識別し、未認証クライアントが読み書きできる内容を報告します。無料、インストール不要、カード登録不要。

  • 無料プラン — 月 3 回のスキャン、サインアップにカード不要。
  • パッシブな BaaS フィンガープリント — ドメイン所有確認不要。
  • Supabase、Firebase、Clerk、Auth0、Appwrite ほか。
  • すべての検出結果に AI 修正プロンプト — Cursor / Claude Code にそのまま貼り付け可能。
Firebase ルールスキャナ: 開いている Firestore、Realtime Database、Storage ルールを検出 — Docs · FixVibe