Firebase セキュリティ ルールでは、さまざまな複雑性と粒度をサポートする、柔軟で強力なカスタム言語を活用します。アプリに応じて具体的または一般的なセキュリティ ルールを作成できます。Realtime Database ルールでは、JavaScript に似た JSON 構造の構文を使用します。Cloud Firestore ルールと Cloud Storage ルールでは、Common Expression Language(CEL)をベースとした言語を使用し、CEL に基づいて match
ステートメントと allow
ステートメントで条件付きのアクセス権付与をサポートします。
ただし、これらはカスタム言語であるため、習得に時間がかかります。このガイドでより複雑なルールの詳細を確認する中で、セキュリティ ルール言語の理解を深めてください。
ルールの詳細を確認するプロダクトを選択してください。
基本構造
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 つ以上のメソッド。これらのメソッドに対して実行を許可します。標準メソッドはget
、list
、create
、update
、delete
です。read
とwrite
は、指定したデータベースまたはストレージのパスへの広範な読み取りや書き込みアクセスを可能にするコンビニエンス メソッドです。 - パス: データベースまたはストレージの場所。URI パスとして表されます。
- ルール:
allow
ステートメント。このステートメントに組み込まれた条件で true と評価されると、リクエストが許可されます。
それぞれのコンセプトの詳細について、以下で説明します。
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 つ以上のメソッド。これらのメソッドに対して実行を許可します。標準メソッドはget
、list
、create
、update
、delete
です。read
とwrite
は、指定したデータベースまたはストレージのパスへの広範な読み取りや書き込みアクセスを可能にするコンビニエンス メソッドです。 - パス: データベースまたはストレージの場所。URI パスとして表されます。
- ルール:
allow
ステートメント。このステートメントに組み込まれた条件で true と評価されると、リクエストが許可されます。
それぞれのコンセプトの詳細について、以下で説明します。
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 Storage でのルールの基本要素は次のとおりです。
service
宣言: ルールを適用する Firebase プロダクトを宣言します。match
ブロック: ルールを適用する、データべースまたはストレージ バケット内のパスを定義します。allow
ステートメント: アクセス権を付与する条件を指定します。条件はメソッドによって異なります。サポートされているメソッドには、get
、list
、create
、update
、delete
と、コンビニエンス メソッドのread
とwrite
が含まれます。- オプションの
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 つのみです。
service cloud.firestore {
// Your 'match' blocks with their corresponding 'allow' statements and
// optional 'function' declarations are contained here
}
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 Firestore と Cloud Storage でのルールの基本要素は次のとおりです。
service
宣言: ルールを適用する Firebase プロダクトを宣言します。match
ブロック: ルールを適用する、データべースまたはストレージ バケット内のパスを定義します。allow
ステートメント: アクセス権を付与する条件を指定します。条件はメソッドによって異なります。サポートされているメソッドには、get
、list
、create
、update
、delete
と、コンビニエンス メソッドのread
とwrite
が含まれます。- オプションの
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 つのみです。
service cloud.firestore {
// Your 'match' blocks with their corresponding 'allow' statements and
// optional 'function' declarations are contained here
}
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 セキュリティ ルールの 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 つ(read
と write
)は、受信リクエストのメソッドに適用されます。もう 1 つの validate
ルールは、データ構造を強制してデータの形式と内容を検証します。.validate
ルールによるアクセス権の付与を確認した後、.write
ルールを適用します。
ルールの種類 | |
---|---|
.read | ユーザーによるデータの読み取りを許可するときに記述します。 |
.write | ユーザーによるデータの書き込みを許可するときに記述します。 |
.validate | 値の適切な形式、子属性の有無、データ型を定義します。 |
デフォルトでは、該当するパスのアクセスを許可するルールがない場合、アクセスは拒否されます。
条件の作成
条件は、特定のオペレーションを許可するか拒否するかを決定するブール式です。request
変数と resource
変数によって、条件のコンテキストが提供されます。
request
変数
request
変数には、以下のフィールドとそれぞれのフィールドに対応する情報が含まれます。
request.auth
Firebase Authentication から取得した認証情報を含む JSON Web Token(JWT)。auth
トークンには、一連の標準クレームと、ユーザーが Firebase Authentication を使用して作成したカスタム クレームが含まれます。詳細については、Firebase セキュリティ ルールと Authentication をご覧ください。
request.method
request.method
は、標準メソッドのいずれか、またはカスタム メソッドです。すべての読み取り専用や書き込み専用の標準メソッドそれぞれに適用されるルールの作成を簡単にするため、コンビニエンス メソッドの read
と write
もあります。
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 のセキュリティ ルールでの演算子とそれぞれの優先順位については、次の表を参考にしてください。
次の表では、任意の式 a
と b
、フィールド 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 項式 | 左から右 |
条件は、特定のオペレーションを許可するか拒否するかを決定するブール式です。request
変数と resource
変数によって、条件のコンテキストが提供されます。
request
変数
request
変数には、以下のフィールドとそれぞれのフィールドに対応する情報が含まれます。
request.auth
Firebase Authentication から取得した認証情報を含む JSON Web Token(JWT)。auth
トークンには、一連の標準クレームと、ユーザーが Firebase Authentication を使用して作成したカスタム クレームが含まれます。詳細については、Firebase セキュリティ ルールと Authentication をご覧ください。
request.method
request.method
は、標準メソッドのいずれか、またはカスタム メソッドです。すべての読み取り専用や書き込み専用の標準メソッドそれぞれに適用されるルールの作成を簡単にするため、コンビニエンス メソッドの read
と write
もあります。
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 のセキュリティ ルールでの演算子とそれぞれの優先順位については、次の表を参考にしてください。
次の表では、任意の式 a
と b
、フィールド 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 セキュリティ ルールでは、以下の方法で条件を定義できます。
事前定義された変数
いくつかの役に立つ変数があらかじめ定義されており、ルールの定義内でアクセスできるようになっています。それぞれの概要は次のとおりです。
事前定義された変数 | |
---|---|
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" } } }
データに基づくルール
ルールでは、データベース内の任意のデータを使用できます。事前定義された変数 root
、data
、newData
を使用すると、書き込みイベントの前後に存在するとおりに任意のパスにアクセスできます。
次の例を見てみましょう。この例では、/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 セキュリティ ルールでは、条件文で変数を組み合わせるために使用できるいくつもの演算子をサポートしています。演算子の一覧については、リファレンス ドキュメントをご覧ください。
条件の作成
実際の条件は、付与するアクセス権によって異なります。ルールでは意図的にかなりの柔軟性を提供しているため、アプリのルールを必要に応じて単純にも複雑にもできます。
本番環境対応の単純なセキュリティ ルールを作成する際のガイダンスについては、基本的なセキュリティ ルールをご覧ください。