// 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 つが含まれています:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if true;
}
}
}Firebase はかつてこれらのルールに 30 日間の自動期限を追加していました。それは変わりました: 今日では、開発者がそれらを置き換えない限り、ルールは永遠に持続します。AI コーディングツールは — テストモードブロックを含む数年分のドキュメントで訓練されているため — それを逐語的に発し、開発者に「これがあなたのセキュリティルールです」と伝えることがよくあります。そうではありません。
本番に現れるが同様に許容的な他のバリアント:
// 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} がユーザーが触れることのできる唯一のドキュメントになります。
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.
{
"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] 配下に保存し、パスで所有権を強制します。
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:rules、firebase deploy --only database、firebase deploy --only storage。FixVibe スキャンを再実行して新しいルールが本番に反映されていることを検証します — baas.firebase-rules の検出結果はクリアされるはずです。
firebase deploy --only firestore:rules
firebase deploy --only database
firebase deploy --only storageFirebase 組み込みツールとの比較
Firebase コンソールは現在のルールを表示しますが、ランタイムの挙動と照らし合わせて監査することはありません。Firebase ルールシミュレータは合成リクエストに対してルールロジックをテストさせてくれます — 有用ですがローカルです。どちらのツールも、公開インターネット上の匿名攻撃者にあなたの本番ルールが実際に何を返すかは教えてくれません。 FixVibe のような外部スキャナ (または手動構成された Burp Suite) だけが、攻撃者と同じ角度から探ります。Google 自身の App Check は悪用を緩和しますが、正しくスコープされたルールの代わりにはなりません。
よくある質問
スキャナは私の Firestore データを読んだり変更したりしますか?
パッシブスキャンは、ルールが許可するかを確認するために、サービスごとに最大 1 回の匿名読み取りを発行します。スキャナはレスポンス形状とデータの存在を記録するだけで、ページングしたり、ドキュメントを列挙したり、書き込んだりはしません。書き込みプローブは検証済みドメイン所有権の背後でゲートされ、未検証のターゲットに対しては実行されません。
私の Firebase プロジェクトが App Check を使用している場合はどうなりますか?
App Check は未認証リクエストを 403 で拒否します。App Check トークンを持たないスキャナはすべてのプローブで 403 を見ます — それが正しい結果です。App Check はルール正確性の代替ではない (盗まれた App Check トークンと開いたルールの組み合わせは依然としてデータを漏洩します) が、機会主義的な外部スキャンをブロックします。
スキャナは部分的なルール設定ミス (読み取りは開、書き込みは閉) を検出できますか?
はい — 各ルール (allow read、allow 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 設定ミススキャナをお読みください。
