Cloud Storage 用の Firebase セキュリティ ルール言語の基本構文について学ぶ

Cloud Storage 用の Firebase Security Rules を使用すると、Cloud Storage バケットに保存されているオブジェクトへのアクセスを制御できます。ルールの構文は柔軟であり、Cloud Storage バケットへのすべての書き込みから特定のファイルに対するオペレーションまで、あらゆるオペレーションを制御するルールを作成できます。

このガイドでは、完全なルールセットを作成するための Cloud Storage Security Rules の基本構文と構造について説明します。

サービスとデータベースの宣言

Cloud Storage 用の Firebase Security Rules は、常に次の宣言で始まります。

service firebase.storage {
    // ...
}

service firebase.storage という宣言では、ルールのスコープを Cloud Storage とし、Cloud Storage Security RulesCloud Firestore などの他のプロダクトのルール間の競合を防止します。

基本的な読み取り / 書き込みのルール

基本的なルールは、Cloud Storage バケットを識別する match ステートメント、ファイル名を指定する match ステートメント、指定されたデータの読み取りを許可するときに詳細を指定する allow 式で構成されます。allow 式では、関連するアクセス方法(読み取り、書き込みなど)と、アクセスを許可または拒否する条件を指定します。

デフォルトのルールセットでは、最初の match ステートメントで {bucket} ワイルドカード式が使用されており、ルールがプロジェクト内のすべてのバケットに適用されることを示しています。ワイルドカードの一致については、次のセクションで詳しく説明します。

service firebase.storage {
  // The {bucket} wildcard indicates we match files in all Cloud Storage buckets
  match /b/{bucket}/o {
    // Match filename
    match /filename {
      allow read: if <condition>;
      allow write: if <condition>;
    }
  }
}

すべての match ステートメントはファイルを指します。match ステートメントでは、match /images/profilePhoto.png のように特定のファイルを指すことができます。

一致ワイルドカード

単一のファイルを指すだけでなく、Rules ではワイルドカードを使用して、名前に特定の接頭辞が含まれるすべてのファイルを指すこともできます。接頭辞を指定するには、match /images/{imageId} のようにスラッシュを含めます。

上の例では、match ステートメントで {imageId} ワイルドカード構文を使用しています。つまり、このルールは、/images/profilePhoto.png/images/croppedProfilePhoto.png のように、名前の先頭に /images/ が付いたすべてのファイルに適用されます。match ステートメントの allow 式が評価されるときに、imageId 変数は、profilePhoto.pngcroppedProfilePhoto.png などの画像ファイル名に解決されます。

ワイルドカード変数は、match の指定ファイル名またはパス認証から参照できます。

// Another way to restrict the name of a file
match /images/{imageId} {
  allow read: if imageId == "profilePhoto.png";
}

階層データ

前述のように、Cloud Storage バケット内に階層構造はありません。しかし、ファイル名の命名規則、多くの場合、ファイル名にスラッシュを含める命名規則を使用することにより、ネストされた一連のディレクトリやサブディレクトリのような構造を模倣できます。Firebase Security Rules とこれらのファイル名の相互作用の仕組みを理解することが重要です。

名前がすべて /images/ という要素で始まるファイルのセットという状況を考えてみましょう。Firebase Security Rules は一致したファイル名にのみ適用されるため、/images/ 要素に対して定義されたアクセス制御は /mp3s/ 要素には適用されません。 代わりに、異なるファイル名パターンに一致する明示的なルールを記述します。

service firebase.storage {
  match /b/{bucket}/o {
    match /images/{imageId} {
      allow read, write: if <condition>;
    }

    // Explicitly define rules for the 'mp3s' pattern
    match /mp3s/{mp3Id} {
      allow read, write: if <condition>;
    }
  }
}

match ステートメントをネストする場合、内部の match ステートメントのパスは、必ず外部の match ステートメントのパスの後ろに付加されます。したがって、次の 2 つのルールセットは同等です。

service firebase.storage {
  match /b/{bucket}/o {
    match /images {
      // Exact match for "images/profilePhoto.png"
      match /profilePhoto.png {
        allow write: if <condition>;
      }
    }
  }
}
service firebase.storage {
  match /b/{bucket}/o {
    // Exact match for "images/profilePhoto.png"
    match /images/profilePhoto.png {
      allow write: if <condition>;
      }
  }
}

再帰一致ワイルドカード

ファイル名の最後の文字列を一致させてその文字列を返すワイルドカードだけでなく、複数のセグメントのワイルドカードを宣言し、ワイルドカード名に =** を追加することによって({path=**} のように)、より複雑な一致を作成することができます。

// Partial match for files that start with "images"
match /images {

  // Exact match for "images/**"
  // e.g. images/users/user:12345/profilePhoto.png is matched
  // images/profilePhoto.png is also matched!
  match /{allImages=**} {
    // This rule matches one or more path segments (**)
    // allImages is a path that contains all segments matched
    allow read: if <other_condition>;
  }
}

複数のルールが 1 つのファイルと一致する場合、結果は、すべてのルール評価の結果の OR になります。つまり、ルールのどれかでファイルの一致が true になると、結果は true になります。

上記のルールでは、ファイル「images/profilePhoto.png」は condition または other_condition が true になると、読み取り可能になります。これに対して、ファイル「images/users/user:12345/profilePhoto.png」に影響する条件は other_condition の結果だけです。

Cloud Storage Security Rules はカスケード処理されません。ルールは、リクエストパスと、ルールで指定されているパスが一致する場合のみ評価されます。

バージョン 1

Firebase Security Rules はデフォルトでバージョン 1 を使用します。バージョン 1 では、再帰ワイルドカードは 1 個以上のファイル名要素と一致します。0 個以上のファイル名要素ではありません。そのため、match /images/{filenamePrefixWildcard}/{imageFilename=**} は /images/profilePics/profile.png のようなファイル名と一致しますが、/images/badge.png のようなファイル名とは一致しません。代わりに /images/{imagePrefixorFilename=**} を使用してください。

再帰ワイルドカードは、match ステートメントの最後に指定する必要があります。

より強力な機能を利用するには、バージョン 2 の使用をおすすめします。

バージョン 2

バージョン 2 の Firebase Security Rules では、再帰ワイルドカードは 0 個以上のパスアイテムに一致します。そのため、/images/{filenamePrefixWildcard}/{imageFilename=**} はファイル名 /images/profilePics/profile.png、/images/badge.png のいずれとも一致します。

セキュリティ ルールの先頭に rules_version = '2'; を追加して、バージョン 2 にオプトインする必要があります。

rules_version = '2';
service cloud.storage {
  match /b/{bucket}/o {
   ...
 }
}

match ステートメントごとに使用できる再帰ワイルドカードは 1 つだけですが、バージョン 2 では、このワイルドカードを match ステートメント内の任意の場所に配置できます。次に例を示します。

rules_version = '2';
service firebase.storage {
 match /b/{bucket}/o {
   // Matches any file in a songs "subdirectory" under the
   // top level of your Cloud Storage bucket.
   match /{prefixSegment=**}/songs/{mp3filenames} {
     allow read, write: if <condition>;
   }
  }
}

詳細なオペレーション

状況によっては、readwrite をより詳細なオペレーションに分割すると便利です。たとえば、アプリの中でファイルの作成とファイルの削除に対して異なる条件を適用したい場合があります。

read オペレーションは getlist に分割できます。

write ルールは createupdatedelete に分割できます。

service firebase.storage {
  match /b/{bucket}/o {
    // A read rule can be divided into read and list rules
    match /images/{imageId} {
      // Applies to single file read requests
      allow get: if <condition>;
      // Applies to list and listAll requests (Rules Version 2)
      allow list: if <condition>;

    // A write rule can be divided into create, update, and delete rules
    match /images/{imageId} {
      // Applies to writes to file contents
      allow create: if <condition>;

      // Applies to updates to (pre-existing) file metadata
      allow update: if <condition>;

      // Applies to delete operations
      allow delete: if <condition>;
    }
  }
 }
}

match ステートメントの重複

1 つのファイル名が複数の match ステートメントと一致する可能性があります。複数の allow 式がリクエストと一致する場合、いずれかの条件が true と評価されると、アクセスが許可されます。

service firebase.storage {
  match b/{bucket}/o {
    // Matches file names directly inside of '/images/'.
    match /images/{imageId} {
      allow read, write: if false;
    }

    // Matches file names anywhere under `/images/`
    match /images/{imageId=**} {
      allow read, write: if true;
    }
  }
}

上記の例では、/images/ でファイル名が始まるファイルへのすべての読み取りと書き込みが許可されます。これは、最初のルールが false であっても、2 番目のルールは常に true であるためです。

ルールはフィルタではない

データを保護してファイル オペレーションの実行を開始する際には、セキュリティ ルールはフィルタではないことにご注意ください。ファイル名パターンに一致するファイルのセットに対してオペレーションを実行することはできません。また、Cloud Storage がアクセスできるのは、現在のクライアントがアクセス権を所有しているファイルのみです。

たとえば、次のセキュリティ ルールがあるとします。

service firebase.storage {
  match /b/{bucket}/o {
    // Allow the client to read files with contentType 'image/png'
    match /aFileNamePrefix/{aFileName} {
      allow read: if resource.contentType == 'image/png';
    }
  }
}

拒否: 結果セットには、contentTypeimage/png でないファイルを含めることができるため、このルールでは次のリクエストは拒否されます。

ウェブ
filesRef = storage.ref().child("aFilenamePrefix");

filesRef.listAll()
    .then(function(result) {
      console.log("Success: ", result.items);
    })
});

Cloud Storage Security Rules のルールでは、その結果の可能性に対して各クエリを評価し、クライアントが読み取り権限を持たないファイルが返された場合にリクエストを失敗させます。アクセス リクエストは、ルールで設定されている制約に従う必要があります。

次のステップ

Cloud Storage 用の Firebase Security Rules についての理解を深めるには、以下をご覧ください。

  • ルール言語の次の主要なコンセプトである動的条件について学習します。動的条件では、ルールにより、ユーザー認可の確認、既存データと受信データの比較、受信データの検証などを行うことができます。

  • 一般的なセキュリティのユースケースと、それらのユースケースに対処する Firebase Security Rules 定義を確認します。

Cloud Storage 固有の Firebase Security Rules のユースケースをご覧ください。