Cloud Storageセキュリティルールの書き方について紹介しましす。
Firebaseでセキュリティルールが設定できるサービスは、Realtime Database・Cloud Storage・Cloud Firestoreの3つあります。
今回は、Cloud Storageを対象にセキュリティルールをまとめます。
目次
Cloud Storageのセキュリティルール
基本的なCloud Storage セキュリティルール条件の例をまとめておきます。
セキュリティルールのread/writeのルールはシンプルで、何も指定がなければドキュメントに対する読み取り・書き込みは拒否されます。そのため、基本的には許可制のルールを書いていくことになります。
デフォルトセキュリティルール
Cloud Storageのセキュリティルールでは、まず service(firebase.storage)と、ルールの評価対象となる Cloud Storage バケット(match /b/{bucket}/o 経由)を指定します。
request.authで認証されたユーザの場合のみ読み取り・書き込みが可能のルールとなっています。{allPaths=**}で全てのディレクトリが対象となっています。
このデフォルトのルールにはFirebase Authenticationが必要です。
1 2 3 4 5 6 7 | service firebase.storage { match /b/{bucket}/o { match /{allPaths=**} { allow read, write: if request.auth != null; } } } |
公開セキュリティルール
先ほどのif request.auth != null;外すことで、認証済みのユーザを判定することなく、全てのユーザが読み取り・書き込みが可能になります。
1 2 3 4 5 6 7 | service firebase.storage { match /b/{bucket}/o { match /{allPaths=**} { allow read, read; } } } |
ユーザセキュリティルール
リクエストされたユーザのUID(request.auth.uid)とユーザUIDのディレクトリが一致した場合のみ読み取り・書き込みが可能になります。
1 2 3 4 5 6 7 | service firebase.storage { match /b/{bucket}/o { match /user/{userId}/{allPaths=**} { allow read, write: if request.auth.uid == userId; } } } |
非公開セキュリティルール
if false;にすることで非公開(読み取り・書き込み)にすることができます。
1 2 3 4 5 6 7 | service firebase.storage { match /b/{bucket}/o { match /{allPaths=**} { allow read, write: if false; } } } |
アクセス権について
allow式で使用するアクセス権にはreadとwriteの2つがあり、さらに細かくreadにはget・list、writeにはcreate・update・deleteがあります。
read
- get:単一のドキュメントの内容を取得
- list:複数のドキュメントの内容を取得
write
- create:新規ドキュメントの追加
- update:既存ドキュメントの更新
- delete:ドキュメントの削除
また、いずれかの「allow式」の条件が trueと判定されると許可されます。
同じコレクションに対するルールが競合している場合、許可設定が優先されます。
再帰ワイルドカード
セキュリティルールは、条件を書いたそのドキュメントの階層にのみに適応され、下層にあたるサブコレクションには適応されません。
だからといって、ディレクトリの深い階層のルールを記述する場合、各階層のサブコレクション全てについてルールを記述するのは非効率的です。
そのような場合、以下のように「再帰ワイルドカード構文 {document=**} 」を使うと便利になります。
testsコレクション以下の全てのドキュメントに対するルールを適用させることができます。
1 2 3 4 5 6 7 | service firebase.storage { match /b/{bucket}/o { match /tests/{document=**} { allow read, write: if true; } } } |
またmatch文のpathのワイルドカード変数のあとに =** を付与してあげることで、下層のサブコレクション全てに同じルールが適応されます。
1 2 3 4 5 6 7 | service firebase.storage { match /b/{bucket}/o { match /users/{userID=**} { allow read: if request.auth != nil; } } } |
バージョン2では、 match /{path=**}/users/{user} のように任意の場所に再帰ワイルドカードを配置できますが、バージョン1ではステートメントの最後にだけしか配置できません。
セキュリティルール条件の関数化
以下のようにセキュリティルールを関数化することができます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | service firebase.storage { match /b/{bucket}/o { function isAuth() { return request.auth.uid != null; } match /users/{user} { allow read: if isAuth(); match /goods/{child} { allow read: if isAuth(); allow write: if isAuth(); } } } } |
「お使いの cloud firestore データベースはクライアントからのリクエストを拒否しています。セキュリティ ルールをアップデートするまでこの状態が続きます」への対処法
突如、クライアントからFirebaseへのリクエストがはじかれ、コンソールをみると、「お使いの cloud firestore データベースはクライアントからのリクエストを拒否しています。セキュリティ ルールをアップデートするまでこの状態が続きます」との通知が。。
今回はFirebase Firestorageのセキュリティルールが甘かったため、セキュリティを強化することで解決しました。
開発中はオープンアクセスを許可するようにルールを設定している場合でも、デプロイし運用していく前には、セキュリティルールの確認と更新の作業が必要です。
それぞれのコンテンツ所有者のみの読み取りと書き込みのアクセス権を制限することで、ユーザーのデータを適切に保護することができます。