マガジン

Firebaseのセキュリティルールを初学者がAIと読む:誰が読み書きできるかの確認表

AIを使いこなす

Claudeで執筆し、GPTで自動校閲・修正しています。

三つの確認項目の表とコードを示す紙を照らし合わせるイラスト
記事の内容をもとに制作したAI生成イメージです。実際の製品画面や検証結果の写真ではありません。

結論から言うと、AIが書いたFirestoreのルールは「アプリが動いたか」ではなく、「ログインしていない人や別のユーザーが、読み書きできないか」で確かめます。そのために、ルールを1行ずつ「誰が・何を・どの条件で」に分けた表を作り、通したい操作と通したくない操作の両方を試してから公開します。 セキュリティルールは、Firebaseのデータベースに対する許可の一覧です。Firestoreではルールに書かれていない操作は許可されません。公式ドキュメントでも、許可は allow 文で明示する形(既定は拒否)として説明されています(条件の書き方)。つまり、アプリが動くのは「どこかの allow が通した」ということです。その allow が広すぎないかを見るのが、この記事の確認作業です。

この記事の目次
  1. まず読み方の骨格:match・allow・条件
  2. 分解表:ルールを「誰が・何を・どの条件で」に直す
  3. 説明用の例:メモアプリのルール
  4. AIへの依頼文:書かせるより、表にさせる
  5. 公開前の確認手順
  6. 公式ドキュメントで確認する箇所
  7. 公開してよいかの判断表

まず読み方の骨格:match・allow・条件

Firestoreのルールは、service cloud.firestore の中に match(どのパスか)と allow(どの操作を、どの条件で許すか)を並べて書きます。操作は read と write にまとめることも、get/list、create/update/delete に分けることもできます(ルールの構造)。

初学者がつまずきやすい点は次の3つです。

  • {document=**} のような再帰ワイルドカードは、ルールのバージョンによって一致する範囲が異なります。バージョン2では0階層以上に一致します。
  • 同じドキュメントに複数の match が当てはまる場合、どれか1つの allow が通れば許可されます(OR)。あとから足した厳しいルールが、残っている緩いルールに打ち消されることがあります。
  • ルールはフィルターではありません。読めないドキュメントを含み得るクエリは、一部だけ返されず、全体が拒否されます(クエリとルール)。

分解表:ルールを「誰が・何を・どの条件で」に直す

AIが出したルールを、次の表に1 allow = 1行で書き写します。空欄が出たら、そこが理解できていない箇所です。

  • (例)/users/{userId}/memos/{memoId}、誰が:ログイン済みで、自分のuidと一致する人、何を:読む、どの条件で:request.auth.uid == userId、通したくない相手は?:未ログイン、別ユーザー
  • 同上、誰が:同上、何を:作成、どの条件で:上記+titleが文字列で100文字以下、通したくない相手は?:型や長さが違うデータ
  • /publicPosts/{postId}、誰が:誰でも、何を:読む、どの条件で:if true、通したくない相手は?:(意図して公開)
  • 同上、誰が:誰も、何を:書く、どの条件で:if false、通したくない相手は?:全員

条件に出てくる語は、公式の説明では次のように使い分けられています。

  • request.auth:ログインしていなければ null。request.auth.uid はログイン中のユーザーID。
  • resource.data:いま保存されているデータ。
  • request.resource.data:これから書き込まれようとしているデータ。

「誰が」の欄に「ログイン済みなら誰でも」と書くことになった行は要注意です。ログインさえすれば他人のデータも読み書きできる状態を意味するからです。

説明用の例:メモアプリのルール

次は、解説のために作った説明用の例です。私が実際にFirebaseで動かして検証したものではありません。コレクション構成も仮定です。

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {

    // 自分のメモだけ
    match /users/{userId}/memos/{memoId} {
      allow read, delete: if request.auth != null
                          && request.auth.uid == userId;
      allow create: if request.auth != null
                    && request.auth.uid == userId
                    && request.resource.data.title is string
                    && request.resource.data.title.size() <= 100;
      allow update: if request.auth != null
                    && request.auth.uid == userId
                    && resource.data.ownerId == request.auth.uid
                    && request.resource.data.ownerId == resource.data.ownerId
                    && request.resource.data.title is string
                    && request.resource.data.title.size() <= 100;
    }

    // 公開記事は誰でも読めるが、アプリからは書けない
    match /publicPosts/{postId} {
      allow read: if true;
      allow write: if false;
    }
  }
}

これに対し、次のような形は、AIが「とりあえず動くように」と出しがちな例です(ここでも仮の例です)。

match /{document=**} {
  allow read, write: if request.auth != null;
}

分解表に直すと「どのパスでも/ログイン済みの誰でも/読み書き全部/条件なし」です。ログインさえ済ませれば他人のメモを読めて消せる、という行になります。動作確認では問題が出ないので、気づきにくい形です。

AIへの依頼文:書かせるより、表にさせる

ルールの生成よりも、読み解きをAIに任せるほうが安全です。次の依頼文をそのまま使えます。【】の部分は差し替えてください。

次のFirestoreセキュリティルールを、1つのallow文ごとに
「パス / 誰が / 何を(get,list,create,update,delete) / 条件 / 条件の弱い点」
の表にしてください。
- 私のアプリの仕様:【例:メモは本人だけが読み書き。公開記事は誰でも閲覧のみ】
- 仕様と合わない行、複数のmatchが重なって許可が広がっている箇所、
  未ログインや別ユーザーでも通る操作を、別に列挙してください。
- 推測は推測と書き、確信がない点は公式ドキュメントのどのページで確認すべきか示してください。
ルール:
【ここに貼る。本物のユーザー名・メールアドレス・キーは入れない】

AIの表は「下書き」です。表の「条件」欄が本当に条件になっているか、ルール本文と見比べるのは人の仕事です。

公開前の確認手順

  1. 仕様を先に3行で書く:誰が何を読み書きしたいのかを、ルールを見る前に文章にします。
  2. 分解表を埋める:AIに作らせた表と、自分で読んだ表を突き合わせます。
  3. 「通ってはいけない操作」を試す:Firebaseコンソールの Rules Playground、またはEmulator Suiteで、次の4パターンを試します(ローカルでのテスト)。
  • 未ログインで読む・書く
  • 別ユーザーとして本人のメモを読む・書く
  • 本人として、想定外の型や長さのデータを書く
  • 本人として、本来読めるはずのデータを読む(通る必要がある側)
  1. クエリとの整合を見る:一覧取得が「自分のドキュメントだけ」に絞られているか。絞らないクエリは、上述のとおり全体が拒否されます。
  2. 残っていないか探す:if true、{document=**}、request.auth != null だけの行、テスト用の時間条件を検索し、意図したものか1つずつ確認します。

繰り返し作業が増えるなら、公式にはユニットテスト用ライブラリ @firebase/rules-unit-testing も紹介されています(上記テストのページ)。

公式ドキュメントで確認する箇所

  • 初期設定、テストモード、反映方法、開くページ:Get started、見るポイント:テストモードの期限の扱い、コンソールまたはFirebase CLIでの反映
  • match・allow・操作の種類、開くページ:ルールの構造、見るポイント:再帰ワイルドカード、重なったmatchの扱い
  • 本人確認、データ検証、開くページ:条件の書き方、見るポイント:request.auth、resource.data、request.resource.data、get()
  • 一覧取得が失敗する、開くページ:クエリとルール、見るポイント:ルールがフィルターではないこと
  • 公開前の試験、開くページ:ローカルでのテスト、見るポイント:Playground、Emulator、ユニットテスト

条件で get() を使って別ドキュメントから権限を引く形は、読み取り課金や評価回数の制限に関わるとされています。AIが get() を多用するルールを出してきたら、条件の書き方のページで制限の記述を確認してください。そのほか、公式ドキュメントのセキュリティ節に「Fix insecure rules」という項目があります。公開前に、自分のルールが該当する書き方になっていないか見ておくと安心です。

公開してよいかの判断表

  • 分解表に空欄がある、判断:公開しない。AIに聞き直し、公式で確認する
  • 未ログイン・別ユーザーの操作が通った、判断:公開しない。該当行を狭める
  • 通ってはいけない操作はすべて拒否、通すべき操作は通った、判断:次へ。型や長さの検証も確認
  • if true が残っている、判断:意図した公開データだけなら可。書き込み側は特に確認

ルールは、アプリのコードとは別にサーバー側で効く許可です。画面上でボタンを隠しても、ルールが許していれば操作は通ります。表と試験の両方がそろって初めて「誰が読み書きできるか」を説明できる状態になります。なお、扱うデータに個人情報が含まれる場合は、ルールだけでなく何を保存するかも見直してください。

出典・参考資料