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設定であれば想定どおりなので、キーが制限されていることだけ確認してください。