セキュリティ ルール言語

Firebase セキュリティ ルールでは、さまざまな複雑性と粒度をサポートする、柔軟で強力なカスタム言語を活用します。アプリに応じて具体的または一般的なセキュリティ ルールを作成できます。Realtime Database ルールでは、JavaScript に似た JSON 構造の構文を使用します。Cloud Firestore ルールと Cloud Storage ルールでは、Common Expression Language(CEL)をベースとした言語を使用し、CEL に基づいて match ステートメントと allow ステートメントで条件付きのアクセス権付与をサポートします。

ただし、これらはカスタム言語であるため、習得に時間がかかります。このガイドでより複雑なルールの詳細を確認する中で、セキュリティ ルール言語の理解を深めてください。

ルールの詳細を確認するプロダクトを選択してください。

基本構造

Cloud Firestore

Cloud Firestore と Cloud Storage の Firebase セキュリティ ルールでは、次の構造と構文を使用します。

service <<name>> {
  // Match the resource path.
  match <<path>> {
    // Allow the request if the following conditions are true.
    allow <<methods>> : if <<condition>>
  }
}

ルールを作成する際は、次の主要なコンセプトの理解が重要です。

  • リクエスト: allow ステートメント内で呼び出される 1 つ以上のメソッド。これらのメソッドに対して実行を許可します。標準メソッドは getlistcreateupdatedelete です。readwrite は、指定したデータベースまたはストレージのパスへの広範な読み取りや書き込みアクセスを可能にするコンビニエンス メソッドです。
  • パス: データベースまたはストレージの場所。URI パスとして表されます。
  • ルール: allow ステートメント。このステートメントに組み込まれた条件で true と評価されると、リクエストが許可されます。

それぞれのコンセプトの詳細について、以下で説明します。

Cloud Storage

Cloud Firestore と Cloud Storage の Firebase セキュリティ ルールでは、次の構造と構文を使用します。

service <<name>> {
  // Match the resource path.
  match <<path>> {
    // Allow the request if the following conditions are true.
    allow <<methods>> : if <<condition>>
  }
}

ルールを作成する際は、次の主要なコンセプトの理解が重要です。

  • リクエスト: allow ステートメント内で呼び出される 1 つ以上のメソッド。これらのメソッドに対して実行を許可します。標準メソッドは getlistcreateupdatedelete です。readwrite は、指定したデータベースまたはストレージのパスへの広範な読み取りや書き込みアクセスを可能にするコンビニエンス メソッドです。
  • パス: データベースまたはストレージの場所。URI パスとして表されます。
  • ルール: allow ステートメント。このステートメントに組み込まれた条件で true と評価されると、リクエストが許可されます。

それぞれのコンセプトの詳細について、以下で説明します。

Realtime Database

Realtime Database では、Firebase セキュリティ ルールは JavaScript のような式で構成されます。これらの式は JSON ドキュメントに格納されます。

ルールでは次の構文を使用します。

{
  "rules": {
    "<<path>>": {
    // Allow the request if the condition for each method is true.
      ".read": <<condition>>,
      ".write": <<condition>>,
      ".validate": <<condition>>
    }
  }
}

ルールには次の 3 つの基本要素があります。

  • パス: データベースの場所。これにはデータベースの JSON 構造が反映されます。
  • リクエスト: ルールでアクセス権を付与するために使用するメソッド。read ルールと write ルールは広範な読み取りや書き込みアクセス権を付与します。一方、validate ルールは 2 次検証として機能し、受信データまたは既存のデータに基づいてアクセス権を付与します。
  • 条件: true と評価された場合にリクエストを許可する条件です。

ルールの構造

Cloud Firestore

Cloud Firestore と Cloud Storage でのルールの基本要素は次のとおりです。

  • service 宣言: ルールを適用する Firebase プロダクトを宣言します。
  • match ブロック: ルールを適用する、データべースまたはストレージ バケット内のパスを定義します。
  • allow ステートメント: アクセス権を付与する条件を指定します。条件はメソッドによって異なります。サポートされているメソッドには、getlistcreateupdatedelete と、コンビニエンス メソッドの readwrite が含まれます。
  • オプションの function 宣言: 複数のルールにわたって使用する条件を結合してラップできます。

service には、リクエストに対してアクセス権を付与する条件を指定する allow ステートメントと併せて 1 つ以上の match ブロックを含めます。ルールの条件では request 変数と resource 変数を利用できます。Firebase セキュリティ ルール言語では function 宣言もサポートしています。

構文のバージョン

syntax ステートメントは、ソースの書き込みに使用された Firebase ルール言語のバージョンを示します。言語の最新バージョンは v2 です。

rules_version = '2';
service cloud.firestore {
...
}

rules_version ステートメントを指定しないと、ルールは v1 エンジンを使用して評価されます。

Service

service 宣言は、ルールを適用する Firebase プロダクト(サービス)を定義します。ソースファイルごとに組み込める service 宣言は 1 つのみです。

Cloud Firestore

service cloud.firestore {
 // Your 'match' blocks with their corresponding 'allow' statements and
 // optional 'function' declarations are contained here
}

Cloud Storage

service firebase.storage {
  // Your 'match' blocks with their corresponding 'allow' statements and
  // optional 'function' declarations are contained here
}

Firebase CLI を使用して Cloud Firestore と Cloud Storage の両方のルールを定義する場合は、別々のファイルでルールを管理する必要があります。

match

match ブロックは、path パターンを宣言します。このパターンが、リクエストされたオペレーション(受信 request.path)へのパスと照合されます。match の本文には、1 つ以上の、ネストされた match ブロック、allow ステートメント、function 宣言が必要です。ネストされた match ブロック内のパスは、親 match ブロック内のパスからの相対パスです。

path パターンはディレクトリのような名前で、名前には変数やワイルドカードを含めることができます。path パターンを使用して、単一パスセグメントとマルチパス セグメントを照合できます。path にバインドされているすべての変数は、match スコープ内や、path を宣言したネストされたスコープ内で表示されます。

path パターンとの一致は、部分一致または完全一致になります。

  • 部分一致: path パターンが request.path の接頭辞と一致します。
  • 完全一致: path パターンが request.path 全体と一致します。

完全一致の場合、ブロック内のルールが評価されます。部分一致の場合、ネストされたmatch ルールがテストされ、ネストされたいずれかの path完全一致となるかどうかが確認されます。

リクエストを許可するかどうかを判断するために、それぞれの完全 match のルールが評価されます。アクセス権を付与するルールが 1 つでも一致すれば、リクエストは許可されます。アクセス権を付与するルールが 1 つも一致しない場合、リクエストは拒否されます。

// Given request.path == /example/hello/nested/path the following
// declarations indicate whether they are a partial or complete match and
// the value of any variables visible within the scope.
service firebase.storage {
  // Partial match.
  match /example/{singleSegment} {   // `singleSegment` == 'hello'
    allow write;                     // Write rule not evaluated.
    // Complete match.
    match /nested/path {             // `singleSegment` visible in scope.
      allow read;                    // Read rule is evaluated.
    }
  }
  // Complete match.
  match /example/{multiSegment=**} { // `multiSegment` == /hello/nested/path
    allow read;                      // Read rule is evaluated.
  }
}

上記の例に示されているように、path 宣言では次の変数がサポートされます。

  • 単一セグメントのワイルドカード: パスでワイルドカード変数を宣言するには、変数を波括弧で囲みます(例: {variable})。match ステートメント内では、この変数を string として使用できます。
  • 再帰ワイルドカード: 再帰(マルチセグメント)ワイルドカードは、パスまたはパスの下位にある複数のパスセグメントと一致します。このワイルドカードは設定した場所の下位にあるすべてのパスと一致します。この変数を宣言するには、セグメント変数の末尾に =** 文字列を付加します(例: {variable=**})。match ステートメント内では、この変数を path オブジェクトとして使用できます。

allow

match ブロックには 1 つ以上の allow ステートメントを含めます。これらが実際のルールです。allow ルールは 1 つ以上のメソッドに適用できます。Cloud Firestore または Cloud Storage で受信リクエストを許可するには、allow ステートメントに設定された条件で true と評価される必要があります。条件を設定せずに allow ステートメントを作成することもできます(例: allow read)。ただし、allow ステートメントに条件が含まれていない場合、該当するメソッドのリクエストが常に許可されます。

メソッドに対する allow ルールのいずれかが一致すると、リクエストは許可されます。また、より広範なルールでアクセス権を付与する場合、セキュリティ ルールがアクセス権を付与し、アクセスを制限する可能性のあるその他の詳細なルールは無視されます。

すべてのユーザーが自身の所有するすべてのファイルの読み取りや削除を行える次の例について考えてみましょう。より詳細なルールでは、書き込みをリクエストしているユーザーが対象のファイルを所有していて、そのファイルが PNG である場合のみ書き込みを許可します。サブパスのファイルは、PNG でない場合でもすべて削除できます。先行するルールでそれが許可されているためです。

service firebase.storage {
  // Allow the requestor to read or delete any resource on a path under the
  // user directory.
  match /users/{userId}/{anyUserFile=**} {
    allow read, delete: if request.auth != null && request.auth.uid == userId;
  }

  // Allow the requestor to create or update their own images.
  // When 'request.method' == 'delete' this rule and the one matching
  // any path under the user directory would both match and the `delete`
  // would be permitted.

  match /users/{userId}/images/{imageId} {
    // Whether to permit the request depends on the logical OR of all
    // matched rules. This means that even if this rule did not explicitly
    // allow the 'delete' the earlier rule would have.
    allow write: if request.auth != null && request.auth.uid == userId && imageId.matches('*.png');
  }
}

メソッド

allow ステートメントに含まれるメソッドは、同じメソッドの受信リクエストに対してアクセス権を付与します。

メソッド リクエストのタイプ
コンビニエンス メソッド
read あらゆるタイプの読み取りリクエスト
write あらゆるタイプの書き込みリクエスト
標準メソッド
get 単一のドキュメントやファイルを対象とした読み取りリクエスト
list クエリとコレクションを対象とした読み取りリクエスト
create 新しいドキュメントやファイルへの書き込み
update 既存のデータベース ドキュメントへの書き込み、またはファイル メタデータの更新
delete データの削除

同じ match ブロック内で読み取りメソッドを重複させることはできません。重複させると、同じ path 宣言内の書き込みメソッドが競合します。

たとえば、次のルールは失敗します。

service bad.example {
  match /rules/with/overlapping/methods {
    // This rule allows reads to all authenticated users
    allow read: if request.auth != null;

    match another/subpath {
      // This secondary, more specific read rule causes an error
      allow get: if request.auth != null && request.auth.uid == "me";
      // Overlapping write methods in the same path cause an error as well
      allow write: if request.auth != null;
      allow create: if request.auth != null && request.auth.uid == "me";
    }
  }
}

関数

セキュリティ ルールの複雑化に伴い、一連の条件を関数としてラップし、ルールセット全体で再利用できるようにしたい場合があります。セキュリティ ルールはカスタム関数をサポートしています。カスタム関数の構文は JavaScript に少し似ていますが、セキュリティ ルール関数はドメイン固有の言語で記述され、いくつかの重要な制限があります。

  • 関数には 1 つの return ステートメントのみを含めることができます。追加ロジックを含めることはできません。たとえば、ループの実行や外部サービスの呼び出しはできません。
  • 関数は、定義されているスコープから関数と変数に自動的にアクセスできます。たとえば、service cloud.firestore スコープ内で定義された関数は、resource 変数、および get()exists() などの組み込み関数にアクセスできます。
  • 関数は他の関数を呼び出すことはできますが、再帰はできません。コールスタックの深さは合計 20 に制限されています。
  • Rules バージョン v2 では、関数で let キーワードを使用して変数を定義できます。関数には最大 10 個の let バインディングを指定できますが、return ステートメントで終了する必要があります。

関数を定義するには function キーワードを使用します。関数は、0 個以上の引数を取ります。たとえば、上に示した例で使用した 2 つのタイプの条件を 1 つの関数にまとめることができます。

service cloud.firestore {
  match /databases/{database}/documents {
    // True if the user is signed in or the requested data is 'public'
    function signedInOrPublic() {
      return request.auth.uid != null || resource.data.visibility == 'public';
    }

    match /cities/{city} {
      allow read, write: if signedInOrPublic();
    }

    match /users/{user} {
      allow read, write: if signedInOrPublic();
    }
  }
}

では、関数の引数と let 割り当ての例をみてみましょう。let 割り当てステートメントはセミコロンで区切る必要があります。

function isAuthorOrAdmin(userId, article) {
  let isAuthor = article.author == userId;
  let isAdmin = exists(/databases/$(database)/documents/admins/$(userId));
  return isAuthor || isAdmin;
}

isAdmin の割り当てにより、admins コレクションのルックアップが強制されることにご注意ください。不要なルックアップを必要としない遅延評価では、&&(AND)と ||(OR)比較の短絡特性を利用し、isAuthor が true(&& 比較)または false(|| 比較)の場合にのみ、2 番目の関数を呼び出します。

function isAdmin(userId) {
  return exists(/databases/$(database)/documents/admins/$(userId));
}
function isAuthorOrAdmin(userId, article) {
  let isAuthor = article.author == userId;
  // `||` is short-circuiting; isAdmin called only if isAuthor == false.
  return isAuthor || isAdmin(userId);
}

セキュリティ ルールで関数を使用すると、ルールが複雑化した場合に保守しやすくなります。

Cloud Storage

Cloud Firestore と Cloud Storage でのルールの基本要素は次のとおりです。

  • service 宣言: ルールを適用する Firebase プロダクトを宣言します。
  • match ブロック: ルールを適用する、データべースまたはストレージ バケット内のパスを定義します。
  • allow ステートメント: アクセス権を付与する条件を指定します。条件はメソッドによって異なります。サポートされているメソッドには、getlistcreateupdatedelete と、コンビニエンス メソッドの readwrite が含まれます。
  • オプションの function 宣言: 複数のルールにわたって使用する条件を結合してラップできます。

service には、リクエストに対してアクセス権を付与する条件を指定する allow ステートメントと併せて 1 つ以上の match ブロックを含めます。ルールの条件では request 変数と resource 変数を利用できます。Firebase セキュリティ ルール言語では function 宣言もサポートしています。

構文のバージョン

syntax ステートメントは、ソースの書き込みに使用された Firebase ルール言語のバージョンを示します。言語の最新バージョンは v2 です。

rules_version = '2';
service cloud.firestore {
...
}

rules_version ステートメントを指定しないと、ルールは v1 エンジンを使用して評価されます。

Service

service 宣言は、ルールを適用する Firebase プロダクト(サービス)を定義します。ソースファイルごとに組み込める service 宣言は 1 つのみです。

Cloud Firestore

service cloud.firestore {
 // Your 'match' blocks with their corresponding 'allow' statements and
 // optional 'function' declarations are contained here
}

Cloud Storage

service firebase.storage {
  // Your 'match' blocks with their corresponding 'allow' statements and
  // optional 'function' declarations are contained here
}

Firebase CLI を使用して Cloud Firestore と Cloud Storage の両方のルールを定義する場合は、別々のファイルでルールを管理する必要があります。

match

match ブロックは、path パターンを宣言します。このパターンが、リクエストされたオペレーション(受信 request.path)へのパスと照合されます。match の本文には、1 つ以上の、ネストされた match ブロック、allow ステートメント、function 宣言が必要です。ネストされた match ブロック内のパスは、親 match ブロック内のパスからの相対パスです。

path パターンはディレクトリのような名前で、名前には変数やワイルドカードを含めることができます。path パターンを使用して、単一パスセグメントとマルチパス セグメントを照合できます。path にバインドされているすべての変数は、match スコープ内や、path を宣言したネストされたスコープ内で表示されます。

path パターンとの一致は、部分一致または完全一致になります。

  • 部分一致: path パターンが request.path の接頭辞と一致します。
  • 完全一致: path パターンが request.path 全体と一致します。

完全一致の場合、ブロック内のルールが評価されます。部分一致の場合、ネストされたmatch ルールがテストされ、ネストされたいずれかの path完全一致となるかどうかが確認されます。

リクエストを許可するかどうかを判断するために、それぞれの完全 match のルールが評価されます。アクセス権を付与するルールが 1 つでも一致すれば、リクエストは許可されます。アクセス権を付与するルールが 1 つも一致しない場合、リクエストは拒否されます。

// Given request.path == /example/hello/nested/path the following
// declarations indicate whether they are a partial or complete match and
// the value of any variables visible within the scope.
service firebase.storage {
  // Partial match.
  match /example/{singleSegment} {   // `singleSegment` == 'hello'
    allow write;                     // Write rule not evaluated.
    // Complete match.
    match /nested/path {             // `singleSegment` visible in scope.
      allow read;                    // Read rule is evaluated.
    }
  }
  // Complete match.
  match /example/{multiSegment=**} { // `multiSegment` == /hello/nested/path
    allow read;                      // Read rule is evaluated.
  }
}

上記の例に示されているように、path 宣言では次の変数がサポートされます。

  • 単一セグメントのワイルドカード: パスでワイルドカード変数を宣言するには、変数を波括弧で囲みます(例: {variable})。match ステートメント内では、この変数を string として使用できます。
  • 再帰ワイルドカード: 再帰(マルチセグメント)ワイルドカードは、パスまたはパスの下位にある複数のパスセグメントと一致します。このワイルドカードは設定した場所の下位にあるすべてのパスと一致します。この変数を宣言するには、セグメント変数の末尾に =** 文字列を付加します(例: {variable=**})。match ステートメント内では、この変数を path オブジェクトとして使用できます。

allow

match ブロックには 1 つ以上の allow ステートメントを含めます。これらが実際のルールです。allow ルールは 1 つ以上のメソッドに適用できます。Cloud Firestore または Cloud Storage で受信リクエストを許可するには、allow ステートメントに設定された条件で true と評価される必要があります。条件を設定せずに allow ステートメントを作成することもできます(例: allow read)。ただし、allow ステートメントに条件が含まれていない場合、該当するメソッドのリクエストが常に許可されます。

メソッドに対する allow ルールのいずれかが一致すると、リクエストは許可されます。また、より広範なルールでアクセス権を付与する場合、セキュリティ ルールがアクセス権を付与し、アクセスを制限する可能性のあるその他の詳細なルールは無視されます。

すべてのユーザーが自身の所有するすべてのファイルの読み取りや削除を行える次の例について考えてみましょう。より詳細なルールでは、書き込みをリクエストしているユーザーが対象のファイルを所有していて、そのファイルが PNG である場合のみ書き込みを許可します。サブパスのファイルは、PNG でない場合でもすべて削除できます。先行するルールでそれが許可されているためです。

service firebase.storage {
  // Allow the requestor to read or delete any resource on a path under the
  // user directory.
  match /users/{userId}/{anyUserFile=**} {
    allow read, delete: if request.auth != null && request.auth.uid == userId;
  }

  // Allow the requestor to create or update their own images.
  // When 'request.method' == 'delete' this rule and the one matching
  // any path under the user directory would both match and the `delete`
  // would be permitted.

  match /users/{userId}/images/{imageId} {
    // Whether to permit the request depends on the logical OR of all
    // matched rules. This means that even if this rule did not explicitly
    // allow the 'delete' the earlier rule would have.
    allow write: if request.auth != null && request.auth.uid == userId && imageId.matches('*.png');
  }
}

メソッド

allow ステートメントに含まれるメソッドは、同じメソッドの受信リクエストに対してアクセス権を付与します。

メソッド リクエストのタイプ
コンビニエンス メソッド
read あらゆるタイプの読み取りリクエスト
write あらゆるタイプの書き込みリクエスト
標準メソッド
get 単一のドキュメントやファイルを対象とした読み取りリクエスト
list クエリとコレクションを対象とした読み取りリクエスト
create 新しいドキュメントやファイルへの書き込み
update 既存のデータベース ドキュメントへの書き込み、またはファイル メタデータの更新
delete データの削除

同じ match ブロック内で読み取りメソッドを重複させることはできません。重複させると、同じ path 宣言内の書き込みメソッドが競合します。

たとえば、次のルールは失敗します。

service bad.example {
  match /rules/with/overlapping/methods {
    // This rule allows reads to all authenticated users
    allow read: if request.auth != null;

    match another/subpath {
      // This secondary, more specific read rule causes an error
      allow get: if request.auth != null && request.auth.uid == "me";
      // Overlapping write methods in the same path cause an error as well
      allow write: if request.auth != null;
      allow create: if request.auth != null && request.auth.uid == "me";
    }
  }
}

関数

セキュリティ ルールの複雑化に伴い、一連の条件を関数としてラップし、ルールセット全体で再利用できるようにしたい場合があります。セキュリティ ルールはカスタム関数をサポートしています。カスタム関数の構文は JavaScript に少し似ていますが、セキュリティ ルール関数はドメイン固有の言語で記述され、いくつかの重要な制限があります。

  • 関数には 1 つの return ステートメントのみを含めることができます。追加ロジックを含めることはできません。たとえば、ループの実行や外部サービスの呼び出しはできません。
  • 関数は、定義されているスコープから関数と変数に自動的にアクセスできます。たとえば、service cloud.firestore スコープ内で定義された関数は、resource 変数、および get()exists() などの組み込み関数にアクセスできます。
  • 関数は他の関数を呼び出すことはできますが、再帰はできません。コールスタックの深さは合計 20 に制限されています。
  • Rules バージョン v2 では、関数で let キーワードを使用して変数を定義できます。関数には最大 10 個の let バインディングを指定できますが、return ステートメントで終了する必要があります。

関数を定義するには function キーワードを使用します。関数は、0 個以上の引数を取ります。たとえば、上に示した例で使用した 2 つのタイプの条件を 1 つの関数にまとめることができます。

service cloud.firestore {
  match /databases/{database}/documents {
    // True if the user is signed in or the requested data is 'public'
    function signedInOrPublic() {
      return request.auth.uid != null || resource.data.visibility == 'public';
    }

    match /cities/{city} {
      allow read, write: if signedInOrPublic();
    }

    match /users/{user} {
      allow read, write: if signedInOrPublic();
    }
  }
}

では、関数の引数と let 割り当ての例をみてみましょう。let 割り当てステートメントはセミコロンで区切る必要があります。

function isAuthorOrAdmin(userId, article) {
  let isAuthor = article.author == userId;
  let isAdmin = exists(/databases/$(database)/documents/admins/$(userId));
  return isAuthor || isAdmin;
}

isAdmin の割り当てにより、admins コレクションのルックアップが強制されることにご注意ください。不要なルックアップを必要としない遅延評価では、&&(AND)と ||(OR)比較の短絡特性を利用し、isAuthor が true(&& 比較)または false(|| 比較)の場合にのみ、2 番目の関数を呼び出します。

function isAdmin(userId) {
  return exists(/databases/$(database)/documents/admins/$(userId));
}
function isAuthorOrAdmin(userId, article) {
  let isAuthor = article.author == userId;
  // `||` is short-circuiting; isAdmin called only if isAuthor == false.
  return isAuthor || isAdmin(userId);
}

セキュリティ ルールで関数を使用すると、ルールが複雑化した場合に保守しやすくなります。

Realtime Database

前述のように、Realtime Database セキュリティ ルールの 3 つの基本要素として、データベースの JSON 構造を反映するデータベースの場所、リクエストのタイプ、アクセス権を付与する条件があります。

データベースの場所

ルールの構造はデータベースに保存しているデータの構造に従う必要があります。たとえば、メッセージを一覧表示するチャットアプリで、次のようなデータがあるとします。

  {
    "messages": {
      "message0": {
        "content": "Hello",
        "timestamp": 1405704370369
      },
      "message1": {
        "content": "Goodbye",
        "timestamp": 1405704395231
      },
      ...
    }
  }

ルールには、上記の構造を反映する必要があります。例:

  {
    "rules": {
      "messages": {
        "$message": {
          // only messages from the last ten minutes can be read
          ".read": "data.child('timestamp').val() > (now - 600000)",

          // new messages must have a string content and a number timestamp
          ".validate": "newData.hasChildren(['content', 'timestamp']) &&
                        newData.child('content').isString() &&
                        newData.child('timestamp').isNumber()"
        }
      }
    }
  }

上記の例に示されているように、Realtime Database セキュリティ ルールではパスセグメントを照合するために、$location 変数をサポートしています。パス上にある子ノードとルールを照合するには、該当するパスセグメントの前に $ 接頭辞を付加します。

  {
    "rules": {
      "rooms": {
        // This rule applies to any child of /rooms/, the key for each room id
        // is stored inside $room_id variable for reference
        "$room_id": {
          "topic": {
            // The room's topic can be changed if the room id has "public" in it
            ".write": "$room_id.contains('public')"
          }
        }
      }
    }
  }

$variable と定数パス名を併用することもできます。

  {
    "rules": {
      "widget": {
        // a widget can have a title or color attribute
        "title": { ".validate": true },
        "color": { ".validate": true },

        // but no other child paths are allowed
        // in this case, $other means any key excluding "title" and "color"
        "$other": { ".validate": false }
      }
    }
  }

メソッド

Realtime Database のルールには 3 つのタイプがあります。これらのうちの 2 つ(readwrite)は、受信リクエストのメソッドに適用されます。もう 1 つの validate ルールは、データ構造を強制してデータの形式と内容を検証します。.validate ルールによるアクセス権の付与を確認した後、.write ルールを適用します。

ルールの種類
.read ユーザーによるデータの読み取りを許可するときに記述します。
.write ユーザーによるデータの書き込みを許可するときに記述します。
.validate 値の適切な形式、子属性の有無、データ型を定義します。

デフォルトでは、該当するパスのアクセスを許可するルールがない場合、アクセスは拒否されます。

条件の作成

Cloud Firestore

条件は、特定のオペレーションを許可するか拒否するかを決定するブール式です。request 変数と resource 変数によって、条件のコンテキストが提供されます。

request 変数

request 変数には、以下のフィールドとそれぞれのフィールドに対応する情報が含まれます。

request.auth

Firebase Authentication から取得した認証情報を含む JSON Web Token(JWT)。auth トークンには、一連の標準クレームと、ユーザーが Firebase Authentication を使用して作成したカスタム クレームが含まれます。詳細については、Firebase セキュリティ ルールと Authentication をご覧ください。

request.method

request.method は、標準メソッドのいずれか、またはカスタム メソッドです。すべての読み取り専用や書き込み専用の標準メソッドそれぞれに適用されるルールの作成を簡単にするため、コンビニエンス メソッドの readwrite もあります。

request.params

request.params には、request.resource に明確に関連しないものの、評価に役立つ可能性のあるデータが含まれます。実際には、このマップはすべての標準メソッドで空になります。カスタム メソッドでは、マップにリソース以外のデータを含みます。パラメータとして提示されたキーと値の型の名前変更や変更がされないよう注意してください。

request.path

request.path は、対象とする resource のパスです。このパスはサービスからの相対パスです。URL 以外の安全な文字(/ など)を含むパスセグメントは URL でエンコードされます。

resource 変数

resource は、Key-Value ペアのマップとして表される、サービス内の現在の値です。条件内で resource を参照すると、サービスからの値の読み取りが最大 1 回行われます。この検索は、リソースを対象とするサービス関連の割り当てに計上されます。get リクエストでは、resource は拒否された場合にのみ割り当てに計上されます。

演算子と演算子の優先順位

Cloud Firestore と Cloud Storage のセキュリティ ルールでの演算子とそれぞれの優先順位については、次の表を参考にしてください。

次の表では、任意の式 ab、フィールド f、インデックス i を前提としています。

演算子 説明 関連性
a[i] a() a.f インデックス、呼び出し、フィールド アクセス 左から右
!a -a 単項否定 右から左
a/b a%b a*b 乗法演算子 左から右
a+b a-b 加法演算子 左から右
a>b a>=b a<=b 関係演算子 左から右
a in b リストまたはマップ内の存在 左から右
a is type 型の比較。type は、bool、int、float、number、string、list、map、timestamp、duration、path、latlng です。 左から右
a==b a!=b 比較演算子 左から右
a && b 条件付き AND 左から右
a || b 条件付き OR 左から右
a ? true_value : false_value 3 項式 左から右

Cloud Storage

条件は、特定のオペレーションを許可するか拒否するかを決定するブール式です。request 変数と resource 変数によって、条件のコンテキストが提供されます。

request 変数

request 変数には、以下のフィールドとそれぞれのフィールドに対応する情報が含まれます。

request.auth

Firebase Authentication から取得した認証情報を含む JSON Web Token(JWT)。auth トークンには、一連の標準クレームと、ユーザーが Firebase Authentication を使用して作成したカスタム クレームが含まれます。詳細については、Firebase セキュリティ ルールと Authentication をご覧ください。

request.method

request.method は、標準メソッドのいずれか、またはカスタム メソッドです。すべての読み取り専用や書き込み専用の標準メソッドそれぞれに適用されるルールの作成を簡単にするため、コンビニエンス メソッドの readwrite もあります。

request.params

request.params には、request.resource に明確に関連しないものの、評価に役立つ可能性のあるデータが含まれます。実際には、このマップはすべての標準メソッドで空になります。カスタム メソッドでは、マップにリソース以外のデータを含みます。パラメータとして提示されたキーと値の型の名前変更や変更がされないよう注意してください。

request.path

request.path は、対象とする resource のパスです。このパスはサービスからの相対パスです。URL 以外の安全な文字(/ など)を含むパスセグメントは URL でエンコードされます。

resource 変数

resource は、Key-Value ペアのマップとして表される、サービス内の現在の値です。条件内で resource を参照すると、サービスからの値の読み取りが最大 1 回行われます。この検索は、リソースを対象とするサービス関連の割り当てに計上されます。get リクエストでは、resource は拒否された場合にのみ割り当てに計上されます。

演算子と演算子の優先順位

Cloud Firestore と Cloud Storage のセキュリティ ルールでの演算子とそれぞれの優先順位については、次の表を参考にしてください。

次の表では、任意の式 ab、フィールド f、インデックス i を前提としています。

演算子 説明 関連性
a[i] a() a.f インデックス、呼び出し、フィールド アクセス 左から右
!a -a 単項否定 右から左
a/b a%b a*b 乗法演算子 左から右
a+b a-b 加法演算子 左から右
a>b a>=b a<=b 関係演算子 左から右
a in b リストまたはマップ内の存在 左から右
a is type 型の比較。type は、bool、int、float、number、string、list、map、timestamp、duration、path、latlng です。 左から右
a==b a!=b 比較演算子 左から右
a && b 条件付き AND 左から右
a || b 条件付き OR 左から右
a ? true_value : false_value 3 項式 左から右

Realtime Database

条件は、特定のオペレーションを許可するか拒否するかを決定するブール式です。Realtime Database セキュリティ ルールでは、以下の方法で条件を定義できます。

事前定義された変数

いくつかの役に立つ変数があらかじめ定義されており、ルールの定義内でアクセスできるようになっています。それぞれの概要は次のとおりです。

事前定義された変数
now Linux エポックからの現在の時刻(ミリ秒)です。これは、SDK の firebase.database.ServerValue.TIMESTAMP で作成したタイムスタンプの検証に特に役に立ちます。
root Firebase データベース内のルートパスを表す RuleDataSnapshot。これは試みるオペレーションの前に存在したとおりになります。
newData データを表す RuleDataSnapshot。これは、試みるオペレーションの後に存在するデータを表します。これには、書き込まれる新しいデータと既存のデータが含まれます。
data データを表す RuleDataSnapshot。このデータは試みるオペレーションの前に存在したとおりになります。
$ variables ID と動的な子キーを表すために使用するワイルドカード パス。
auth 認証されたユーザーのトークン ペイロードを表します。

これらの変数はルール内の任意の場所で使用できます。たとえば、次のセキュリティ ルールは、/foo/ ノードに書き込まれるデータが 100 文字未満の文字列であることを保証します。

{
  "rules": {
    "foo": {
      // /foo is readable by the world
      ".read": true,

      // /foo is writable by the world
      ".write": true,

      // data written to /foo must be a string less than 100 characters
      ".validate": "newData.isString() && newData.val().length < 100"
    }
  }
}

データに基づくルール

ルールでは、データベース内の任意のデータを使用できます。事前定義された変数 rootdatanewData を使用すると、書き込みイベントの前後に存在するとおりに任意のパスにアクセスできます。

次の例を見てみましょう。この例では、/allow_writes/ ノードの値が true で、親ノードに readOnly フラグが設定されておらず、新しく書き込まれたデータに foo という名前の子がある限り、書き込みオペレーションが許可されます。

".write": "root.child('allow_writes').val() === true &&
          !data.parent().child('readOnly').exists() &&
          newData.child('foo').exists()"

クエリベースのルール

ルールをフィルタとして使用することはできませんが、ルール内のクエリ パラメータを使用してデータのサブセットへのアクセスを制限できます。ルール内で query. 式を使用し、クエリ パラメータに基づいて読み取りまたは書き込みアクセス権を付与します。

たとえば、次のクエリベースのルールでは、ユーザーベースのセキュリティ ルールとクエリベースのルールを使用して、baskets コレクション内のデータへのアクセスを、アクティブ ユーザーが所有する買い物かごのみに制限します。

"baskets": {
  ".read": "auth.uid !== null &&
            query.orderByChild === 'owner' &&
            query.equalTo === auth.uid" // restrict basket access to owner of basket
}

次の、ルール内のクエリ パラメータを含むクエリは、成功します。

db.ref("baskets").orderByChild("owner")
                 .equalTo(auth.currentUser.uid)
                 .on("value", cb)                 // Would succeed

しかし、ルール内のパラメータを含まないクエリは、PermissionDenied エラーで失敗します。

db.ref("baskets").on("value", cb)                 // Would fail with PermissionDenied

クエリベースのルールを使用して、クライアントが読み取りオペレーションでダウンロードできるデータの量を制限することもできます。

たとえば次のルールでは、読み取りアクセスの対象を、優先度順に並べ替えられた最初の 1,000 件のクエリ結果のみに制限します。

messages: {
  ".read": "query.orderByKey &&
            query.limitToFirst <= 1000"
}

// Example queries:

db.ref("messages").on("value", cb)                // Would fail with PermissionDenied

db.ref("messages").limitToFirst(1000)
                  .on("value", cb)                // Would succeed (default order by key)

Realtime Database セキュリティ ルールでは次の query. 式を利用できます。

クエリベースのルールの式
説明
query.orderByKey
query.orderByPriority
query.orderByValue
ブール値 キー、優先度、または値で並べ替えられたクエリの場合は True です。それ以外の場合は false。
query.orderByChild 文字列
null
文字列で子ノードへの相対パスを表します。例: query.orderByChild === "address/zip"クエリが子ノードで並べ替えられていない場合、この値は null です。
query.startAt
query.endAt
query.equalTo
文字列
数値
ブール値
null
実行中のクエリの範囲を取得するか、または範囲が設定されていない場合は null を返します。
query.limitToFirst
query.limitToLast
数値
null
実行中のクエリの制限を取得するか、または制限が設定されていない場合は null を返します。

演算子

Realtime Database セキュリティ ルールでは、条件文で変数を組み合わせるために使用できるいくつもの演算子をサポートしています。演算子の一覧については、リファレンス ドキュメントをご覧ください。

条件の作成

実際の条件は、付与するアクセス権によって異なります。ルールでは意図的にかなりの柔軟性を提供しているため、アプリのルールを必要に応じて単純にも複雑にもできます。

本番環境対応の単純なセキュリティ ルールを作成する際のガイダンスについては、基本的なセキュリティ ルールをご覧ください。