Firebase Summit のすべての発表内容に目を通し、Firebase を活用してアプリ開発を加速し、自信を持ってアプリを実行できる方法をご確認ください。 詳細

CloudFirestoreセキュリティルールの記述条件

このガイドは、構造化セキュリティ ルールガイドに基づいており、Cloud Firestore セキュリティ ルールに条件を追加する方法を示しています。 Cloud Firestore セキュリティ ルールの基本に慣れていない場合は、スタートガイドをご覧ください。

Cloud Firestore セキュリティ ルールの主要な構成要素は条件です。条件は、特定の操作を許可するか拒否するかを決定するブール式です。セキュリティ ルールを使用して、ユーザー認証を確認したり、受信データを検証したり、データベースの他の部分にアクセスしたりする条件を記述します。

認証

最も一般的なセキュリティ ルール パターンの 1 つは、ユーザーの認証状態に基づいてアクセスを制御することです。たとえば、サインインしているユーザーのみがデータを書き込むことをアプリで許可する場合があります。

service cloud.firestore {
  match /databases/{database}/documents {
    // Allow the user to access documents in the "cities" collection
    // only if they are authenticated.
    match /cities/{city} {
      allow read, write: if request.auth != null;
    }
  }
}

別の一般的なパターンは、ユーザーが自分のデータのみを読み書きできるようにすることです。

service cloud.firestore {
  match /databases/{database}/documents {
    // Make sure the uid of the requesting user matches name of the user
    // document. The wildcard expression {userId} makes the userId variable
    // available in rules.
    match /users/{userId} {
      allow read, update, delete: if request.auth != null && request.auth.uid == userId;
      allow create: if request.auth != null;
    }
  }
}

アプリが Firebase Authentication またはGoogle Cloud Identity Platformを使用している場合、 request.auth変数には、クライアントがデータをリクエストするための認証情報が含まれます。 request.authの詳細については、リファレンス ドキュメントを参照してください。

データ検証

多くのアプリは、アクセス制御情報をデータベース内のドキュメントのフィールドとして保存します。 Cloud Firestore セキュリティ ルールは、ドキュメント データに基づいてアクセスを動的に許可または拒否できます。

service cloud.firestore {
  match /databases/{database}/documents {
    // Allow the user to read data if the document has the 'visibility'
    // field set to 'public'
    match /cities/{city} {
      allow read: if resource.data.visibility == 'public';
    }
  }
}

resource変数は要求されたドキュメントを参照し、 resource.dataはドキュメントに保存されているすべてのフィールドと値のマップです。 resource変数の詳細については、リファレンス ドキュメントを参照してください。

データを書き込むときに、受信データを既存のデータと比較したい場合があります。この場合、ルールセットが保留中の書き込みを許可している場合、 request.resource変数にはドキュメントの将来の状態が含まれます。ドキュメント フィールドのサブセットのみを変更するupdate操作の場合、 request.resource変数には操作後の保留中のドキュメント状態が含まれます。 request.resourceのフィールド値をチェックして、不要または不整合なデータ更新を防ぐことができます。

service cloud.firestore {
  match /databases/{database}/documents {
    // Make sure all cities have a positive population and
    // the name is not changed
    match /cities/{city} {
      allow update: if request.resource.data.population > 0
                    && request.resource.data.name == resource.data.name;
    }
  }
}

他のドキュメントにアクセスする

get()およびexists()関数を使用して、セキュリティ ルールは着信要求をデータベース内の他のドキュメントに対して評価できます。 get()およびexists()関数は両方とも、完全に指定されたドキュメント パスを想定しています。変数を使用してget()およびexists() ) のパスを作成する場合、 $(variable)構文を使用して変数を明示的にエスケープする必要があります。

以下の例では、 database変数は match ステートメントmatch /databases/{database}/documentsによって取得され、パスを形成するために使用されます。

service cloud.firestore {
  match /databases/{database}/documents {
    match /cities/{city} {
      // Make sure a 'users' document exists for the requesting user before
      // allowing any writes to the 'cities' collection
      allow create: if request.auth != null && exists(/databases/$(database)/documents/users/$(request.auth.uid))

      // Allow the user to delete cities if their user document has the
      // 'admin' field set to 'true'
      allow delete: if request.auth != null && get(/databases/$(database)/documents/users/$(request.auth.uid)).data.admin == true
    }
  }
}

書き込みの場合、 getAfter()関数を使用して、トランザクションまたは書き込みのバッチが完了した後、トランザクションまたはバッチがコミットされる前に、ドキュメントの状態にアクセスできます。 get()と同様に、 getAfter()関数は完全に指定されたドキュメント パスを取ります。 getAfter()を使用して、トランザクションまたはバッチとして一緒に実行する必要がある一連の書き込みを定義できます。

通話制限へのアクセス

ルール セットの評価ごとのドキュメント アクセス呼び出しには制限があります。

  • 単一ドキュメント リクエストとクエリ リクエストの場合は 10。
  • 複数ドキュメントの読み取り、トランザクション、およびバッチ書き込みの場合は 20。以前の制限である 10 も、各操作に適用されます。

    たとえば、3 つの書き込み操作を含むバッチ書き込み要求を作成し、セキュリティ ルールで 2 つのドキュメント アクセス呼び出しを使用して各書き込みを検証するとします。この場合、各書き込みは 10 回のアクセス呼び出しのうち 2 回を使用し、バッチ化された書き込み要求は 20 回のアクセス呼び出しのうち 6 回を使用します。

いずれかの制限を超えると、許可拒否エラーが発生します。一部のドキュメント アクセス呼び出しはキャッシュされる可能性があり、キャッシュされた呼び出しは制限に対してカウントされません。

これらの制限がトランザクションとバッチ書き込みに与える影響の詳細については、アトミック操作を保護するためのガイドを参照してください。

通話と料金へのアクセス

これらの関数を使用すると、データベースで読み取り操作が実行されます。つまり、ルールが要求を拒否した場合でも、ドキュメントの読み取りに対して課金されます。具体的な請求情報については、 Cloud Firestore の料金をご覧ください。

カスタム関数

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

  • 関数にはreturnステートメントを 1 つだけ含めることができます。追加のロジックを含めることはできません。たとえば、ループを実行したり、外部サービスを呼び出したりすることはできません。
  • 関数は、それらが定義されているスコープから関数と変数に自動的にアクセスできます。たとえば、 service cloud.firestoreスコープ内で定義された関数は、 resource変数とget()exists()などの組み込み関数にアクセスできます。
  • 関数は他の関数を呼び出すことができますが、再帰はできません。呼び出しスタックの深さの合計は 10 に制限されています。
  • ルール バージョン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();
    }
  }
}

セキュリティ ルールで関数を使用すると、ルールの複雑さが増しても保守しやすくなります。

ルールはフィルターではありません

データを保護してクエリの作成を開始したら、セキュリティ ルールはフィルターではないことに注意してください。コレクション内のすべてのドキュメントに対するクエリを記述して、Cloud Firestore が現在のクライアントがアクセス権を持つドキュメントのみを返すことを期待することはできません。

たとえば、次のセキュリティ ルールを考えてみましょう。

service cloud.firestore {
  match /databases/{database}/documents {
    // Allow the user to read data if the document has the 'visibility'
    // field set to 'public'
    match /cities/{city} {
      allow read: if resource.data.visibility == 'public';
    }
  }
}

Denied : このルールは次のクエリを拒否します。これは、 visibilitypublicされていないドキュメントが結果セットに含まれる可能性があるためです。

ウェブ
db.collection("cities").get()
    .then(function(querySnapshot) {
        querySnapshot.forEach(function(doc) {
            console.log(doc.id, " => ", doc.data());
    });
});

Allowed : where("visibility", "==", "public")句により、結果セットがルールの条件を満たしていることが保証されるため、このルールでは次のクエリが許可されます。

ウェブ
db.collection("cities").where("visibility", "==", "public").get()
    .then(function(querySnapshot) {
        querySnapshot.forEach(function(doc) {
            console.log(doc.id, " => ", doc.data());
        });
    });

Cloud Firestore セキュリティ ルールは、潜在的な結果に対して各クエリを評価し、クライアントが読み取り権限を持っていないドキュメントを返す可能性がある場合、リクエストは失敗します。クエリは、セキュリティ ルールによって設定された制約に従う必要があります。セキュリティ ルールとクエリの詳細については、データの安全なクエリを参照してください。

次のステップ