すべての解説
深刻度:重大データベースセキュリティ

Firebase Security Rules:データベースを開けっ放しにしない

FirebaseのWebアプリは、誰でも見られる設定オブジェクトを使って、Firestore、Realtime Database、Cloud Storage をブラウザから直接読み書きします。リクエストを許可するかどうかを決めるのは Security Rules だけです。テストモードのまま放置されたルールや、すべてを許可するように緩められたルールは、データベース全体をインターネットにさらします。

これは何か

Security Rules は、読み取りと書き込みのたびにGoogleのサーバー上で評価される小さなポリシー言語です。各 match ブロックはパス——コレクション、ドキュメント、Storageのフォルダー——を対象とし、allow 文が、どの操作をどの条件で許可するかを指定します。条件には request.auth(誰がリクエストしているか)と request.resource.data(何を書き込もうとしているか)を使います。

Firebaseのweb設定は、apiKey を含めてプロジェクトを識別するだけのものです。シークレットではなく、それ自体ではアクセス権を与えません。だからこそルールが極めて重要なのです。どの訪問者でも、あなたの設定でFirebase SDKを初期化し、自分のブラウザのコンソールからデータベースに直接クエリを送れます。

なぜ重要か

Firestoreのテストモードは、有効期限まですべての読み書きを許可します。期限が来てアプリが動かなくなったとき、よくある「修正」が allow read, write: if true です——これでは、すべてのドキュメントが世界中から読み書き可能になります。露出したFirebaseデータベースは大規模なデータ漏洩の常連の原因であり、見つけるのも抜き取るのも簡単です。

request.auth != null だけをチェックするルールも、大差ありません。誰でもアカウントを作れ、多くの場合は匿名でも作れるため、そのまま全ユーザーのデータを読めてしまいます。書き込みを検証しなければ、ユーザーは本来制御できないはずのフィールドも編集できます——たとえば自分のプロフィールに role: "admin" を設定するといったことです。

直し方

開いたルールを所有者ベースのルールに置き換える

既定で拒否し、コレクションごとにアクセスを許可します。この例では、各ユーザーは users 内の自分のドキュメントだけを読み書きでき、それ以外には一切アクセスできません。

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /users/{userId} {
      allow read, write: if request.auth != null
        && request.auth.uid == userId;
    }
    // Every other path is denied by default.
  }
}
ユーザーが書き込める内容を検証する

ユーザーが変更できるフィールドを制限し、自分で権限を昇格させたり、サーバー側で管理するデータを改ざんしたりできないようにします。affectedKeys().hasOnly() は、ほかのフィールドに触れる更新をすべて拒否します。

match /users/{userId} {
  allow update: if request.auth.uid == userId
    && request.resource.data.diff(resource.data)
         .affectedKeys().hasOnly(["displayName", "photoURL"]);
}
再帰ワイルドカードとテストモードのルールを取り除く

ルールの中から、広い allow と組み合わさった match /{document=**}、if true、そして期限付きのテストモードのタイムスタンプを探してください。Cloud Storage と Realtime Database には別々のルールファイルがあることを忘れずに、そちらも保護しましょう。

攻撃者の視点でルールをテストする

Firebaseコンソールの Rules Playground、または Emulator Suite と @firebase/rules-unit-testing を使い、未認証のユーザーとして、また別のサインイン済みユーザーとして読み取りを実行してください。手早い外部チェックとしては、未認証のRESTリクエストがあります。ドキュメントが返ってきたら、そのコレクションは公開状態です。

curl "https://firestore.googleapis.com/v1/projects/<project-id>/databases/(default)/documents/users"

FAQ

Firebaseの apiKey はシークレットですか?

いいえ。Firebaseのweb設定にある apiKey はプロジェクトを識別するもので、ブラウザに配信される前提です。データは Security Rules で保護し、さらにGoogle Cloudでキーをアプリが実際に使うAPIだけに制限して、ほかの課金対象のGoogleサービスに流用されないようにしてください。

request.auth != null で十分ですか?

ほとんどの場合、不十分です。これはリクエストした人がサインインしていることを示すだけで、データがその人のものであることは示しません。request.auth.uid をドキュメントの所有者と比較するか、ユーザーが自分で設定できないロールをチェックしてください。

AppSafeはFirebaseのルールをチェックしますか?

AppSafeはFirebaseプロジェクトに問い合わせないため、ルールを評価することはできません。Rules Playground か上記のcurlによるチェックを使ってください。ただし、JavaScript内で見つかったGoogleのAPIキー(AIza… 形式)は検出します。同じ形式が Maps や Gemini のような課金対象のサービスにも使われるためです。Firebaseのweb設定であれば想定どおりなので、キーが制限されていることだけ確認してください。

あなたのアプリは大丈夫ですか?

AppSafeなら、この問題を含む数十項目を1回の無料スキャンでチェックできます。

アプリを無料でスキャン