Daten sicher abfragen
Diese Seite basiert auf den Konzepten in den Abschnitten Sicherheitsregeln strukturieren und Schreibbedingungen für Sicherheitsregeln und erläutert die Interaktion von Firestore-Sicherheitsregeln mit Abfragen. Es wird hier näher untersucht, wie Sicherheitsregeln die Abfragen beeinflussen, die Sie schreiben können, und es wird erläutert, wie sich prüfen lässt, ob für Ihre Abfragen die Einschränkungen Ihrer Sicherheitsregeln gelten. Auf dieser Seite wird auch gezeigt, wie Sicherheitsregeln geschrieben werden, die Abfragen anhand von Abfrageattributen wie limit
und orderBy
zulassen oder ablehnen.
Regeln sind keine Filter
Beachten Sie beim Schreiben von Abfragen zum Abrufen von Dokumenten, dass Sicherheitsregeln keine Filter sind. Abfragen beziehen sich immer auf alle Dokumente. Um Zeit und Ressourcen zu sparen, wertet Firestore eine Abfrage anhand der potenziellen Ergebnismenge aus, anstatt die tatsächlichen Feldwerte für alle Ihre Dokumente zu verwenden. Wenn eine Abfrage potenziell Dokumente zurückgibt, für die der Client keine Leseberechtigung hat, schlägt die gesamte Anfrage fehl.
Abfragen und Sicherheitsregeln
Wie die folgenden Beispiele zeigen, müssen Sie Ihre Abfragen so schreiben, dass sie den Einschränkungen Ihrer Sicherheitsregeln entsprechen.
Dokumente basierend auf auth.uid
schützen und abfragen
Das folgende Beispiel zeigt, wie eine Abfrage zum Abrufen von Dokumenten geschrieben wird, die durch eine Sicherheitsregel geschützt sind. Betrachten Sie eine Datenbank, die eine Sammlung von story
-Dokumenten enthält:
/stories/{storyid}
{
title: "A Great Story",
content: "Once upon a time...",
author: "some_auth_id",
published: false
}
Zusätzlich zu den Feldern title
und content
werden in jedem Dokument die Felder author
und published
für die Zugriffssteuerung gespeichert. Bei diesen Beispielen wird davon ausgegangen, dass die Anwendung Firebase Authentication verwendet, die das Feld author
auf die UID setzt, mit der das Dokument erstellt wurde. Die request.auth
-Variable in den Sicherheitsregeln wird auch von der Firebase Authentication festgelegt.
Die folgende Sicherheitsregel verwendet die Variablen request.auth
und resource.data
, damit der Autor den Lese- und Schreibzugriff für jede story
einschränken kann:
service cloud.firestore {
match /databases/{database}/documents {
match /stories/{storyid} {
// Only the authenticated user who authored the document can read or write
allow read, write: if request.auth != null && request.auth.uid == resource.data.author;
}
}
}
Angenommen, Ihre Anwendung enthält eine Seite, auf der dem Nutzer eine Liste der von ihm verfassten story
-Dokumente angezeigt wird. Sie könnten annehmen, dass Sie die folgende Abfrage zum Ausfüllen dieser Seite verwenden können. Diese Abfrage schlägt jedoch fehl, da sie nicht dieselben Einschränkungen wie Ihre Sicherheitsregeln enthält:
Ungültig: Die Abfrageeinschränkungen stimmen nicht mit den Sicherheitsregeln überein
// This query will fail
db.collection("stories").get()
Die Abfrage schlägt fehl, auch wenn der aktuelle Nutzer der Autor jedes story
-Dokuments ist. Wenn Firestore Ihre Sicherheitsregeln anwendet, wird die Abfrage anhand der potenziellen Ergebnismenge ausgewertet und nicht anhand der tatsächlichen Attribute der Dokumente in Ihrer Datenbank. Wenn eine Abfrage potenziell Dokumente umfasst, die gegen Ihre Sicherheitsregeln verstoßen, schlägt die Abfrage fehl.
Im Gegensatz dazu ist die folgende Abfrage erfolgreich, da sie dieselbe Einschränkung für das Feld author
enthält wie die Sicherheitsregeln:
Gültig: Die Abfrageeinschränkungen stimmen mit den Sicherheitsregeln überein
var user = firebase.auth().currentUser;
db.collection("stories").where("author", "==", user.uid).get()
Dokumente anhand eines Felds schützen und abfragen
Um die Interaktion zwischen Abfragen und Regeln weiter zu veranschaulichen, erweitern die unten aufgeführten Sicherheitsregeln den Lesezugriff für die stories
-Sammlung, sodass jeder Nutzer die story
-Dokumente lesen darf, bei denen das Feld published
auf true
gesetzt ist.
service cloud.firestore {
match /databases/{database}/documents {
match /stories/{storyid} {
// Anyone can read a published story; only story authors can read unpublished stories
allow read: if resource.data.published == true || (request.auth != null && request.auth.uid == resource.data.author);
// Only story authors can write
allow write: if request.auth != null && request.auth.uid == resource.data.author;
}
}
}
Die Abfrage für veröffentlichte Seiten muss dieselben Einschränkungen wie die Sicherheitsregeln enthalten:
db.collection("stories").where("published", "==", true).get()
Die Abfrageeinschränkung .where("published", "==", true)
garantiert, dass resource.data.published
für jedes Ergebnis true
ist. Daher erfüllt diese Abfrage die Sicherheitsregeln und darf Daten lesen.
OR
Abfragen
Bei der Auswertung einer logischen OR
-Abfrage (or
, in
oder array-contains-any
) anhand eines Regelsatzes wertet Firestore jeden Vergleichswert separat aus. Jeder Vergleichswert muss die Einschränkungen der Sicherheitsregeln erfüllen. Zum Beispiel für die folgende Regel:
match /mydocuments/{doc} {
allow read: if resource.data.x > 5;
}
Ungültig: Die Abfrage garantiert nicht x > 5
für alle potenziellen Dokumente
// These queries will fail
query(db.collection("mydocuments"),
or(where("x", "==", 1),
where("x", "==", 6)
)
)
query(db.collection("mydocuments"),
where("x", "in", [1, 3, 6, 42, 99])
)
Gültig: Die Abfrage garantiert x > 5
für alle potenziellen Dokumente
query(db.collection("mydocuments"),
or(where("x", "==", 6),
where("x", "==", 42)
)
)
query(db.collection("mydocuments"),
where("x", "in", [6, 42, 99, 105, 200])
)
Einschränkungen bei Abfragen auswerten
Ihre Sicherheitsregeln können auch Abfragen basierend auf ihren Einschränkungen zulassen oder ablehnen.
Die Variable request.query
enthält die Eigenschaften limit
, offset
und orderBy
einer Abfrage. Ihre Sicherheitsregeln können beispielsweise jede Abfrage ablehnen, die die maximale Anzahl von Dokumenten nicht begrenzt, die für einen bestimmten Bereich abgerufen werden können:
allow list: if request.query.limit <= 10;
Der folgende Regelsatz zeigt, wie Sicherheitsregeln geschrieben werden, mit denen Einschränkungen ausgewertet werden, die für Abfragen gelten. In diesem Beispiel wird der vorherige stories
-Regelsatz um die folgenden Änderungen erweitert:
- Der Regelsatz teilt die Leseregel in
get
- undlist
-Regeln auf. - Die
get
-Regel beschränkt den Abruf einzelner Dokumente auf öffentliche Dokumente oder Dokumente, die der Nutzer verfasst hat. - Die
list
-Regel wendet dieselben Einschränkungen wieget
an, nur bei Abfragen. Von dieser Regel wird außerdem das Anfragenlimit geprüft. Danach werden alle Anfragen ohne Limit oder mit einem Limit größer als 10 abgelehnt. - Der Regelsatz definiert eine
authorOrPublished()
-Funktion, um eine Duplizierung des Codes zu vermeiden.
service cloud.firestore {
match /databases/{database}/documents {
match /stories/{storyid} {
// Returns `true` if the requested story is 'published'
// or the user authored the story
function authorOrPublished() {
return resource.data.published == true || request.auth.uid == resource.data.author;
}
// Deny any query not limited to 10 or fewer documents
// Anyone can query published stories
// Authors can query their unpublished stories
allow list: if request.query.limit <= 10 &&
authorOrPublished();
// Anyone can retrieve a published story
// Only a story's author can retrieve an unpublished story
allow get: if authorOrPublished();
// Only a story's author can write to a story
allow write: if request.auth.uid == resource.data.author;
}
}
}
Sammlungsgruppenabfragen und Sicherheitsregeln
Standardmäßig werden Abfragen einer einzelnen Sammlung zugeordnet und sie rufen nur Ergebnisse aus dieser Sammlung ab. Mit Sammlungsgruppenabfragen können Sie Ergebnisse aus einer Sammlungsgruppe abrufen, die aus allen Sammlungen mit derselben ID besteht. In diesem Abschnitt wird beschrieben, wie Sie Ihre Sammlungsgruppenabfragen mithilfe von Sicherheitsregeln sichern.
Dokumente anhand von Sammlungsgruppen schützen und abfragen
Sie müssen in Ihren Sicherheitsregeln das Abfragen von Sammlungsgruppen explizit zulassen und zwar durch Schreiben einer Regel für die Sammlungsgruppe:
- Stellen Sie sicher, dass
rules_version = '2';
die erste Zeile Ihres Regelsatzes ist. Sammlungsgruppenabfragen erfordern das neue rekursive Platzhalterverhalten{name=**}
der Sicherheitsregeln der Version 2. - Erstellen Sie mithilfe von
match /{path=**}/[COLLECTION_ID]/{doc}
eine Regel für Ihre Sammlungsgruppe.
Angenommen, ein Forum ist in forum
-Dokumente mit posts
-Untersammlungen gegliedert:
/forums/{forumid}/posts/{postid}
{
author: "some_auth_id",
authorname: "some_username",
content: "I just read a great story.",
}
In dieser Anwendung veröffentlichen wir Beiträge, die von ihren Eigentümern bearbeitet und von authentifizierten Nutzern gelesen werden können:
service cloud.firestore {
match /databases/{database}/documents {
match /forums/{forumid}/posts/{post} {
// Only authenticated users can read
allow read: if request.auth != null;
// Only the post author can write
allow write: if request.auth != null && request.auth.uid == resource.data.author;
}
}
}
Jeder authentifizierte Nutzer kann die Beiträge jedes einzelnen Forums abrufen:
db.collection("forums/technology/posts").get()
Aber was, wenn Sie dem aktuellen Nutzer die Beiträge in allen Foren zeigen möchten?
Sie können eine Sammlungsgruppenabfrage verwenden, um Ergebnisse aus allen posts
-Sammlungen abzurufen:
var user = firebase.auth().currentUser;
db.collectionGroup("posts").where("author", "==", user.uid).get()
Sie müssen diese Abfrage in Ihren Sicherheitsregeln durch Erstellen einer Lese- oder Listenregel für die Sammlungsgruppe posts
zulassen:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Authenticated users can query the posts collection group
// Applies to collection queries, collection group queries, and
// single document retrievals
match /{path=**}/posts/{post} {
allow read: if request.auth != null;
}
match /forums/{forumid}/posts/{postid} {
// Only a post's author can write to a post
allow write: if request.auth != null && request.auth.uid == resource.data.author;
}
}
}
Beachten Sie jedoch, dass diese Regeln unabhängig von der Hierarchie für alle Sammlungen mit der ID posts
gelten. Diese Regeln gelten beispielsweise für alle folgenden posts
-Sammlungen:
/posts/{postid}
/forums/{forumid}/posts/{postid}
/forums/{forumid}/subforum/{subforumid}/posts/{postid}
Sammlungsgruppenabfragen mit einem Feld sichern
Wie Abfragen einzelner Sammlungen müssen auch Sammlungsgruppenabfragen den in Ihren Sicherheitsregeln festgelegten Einschränkungen entsprechen. Jedem Forumsbeitrag kann beispielsweise ein published
-Feld hinzugefügt werden, wie im obigen stories
-Beispiel gezeigt:
/forums/{forumid}/posts/{postid}
{
author: "some_auth_id",
authorname: "some_username",
content: "I just read a great story.",
published: false
}
Es können dann Regeln für die posts
-Sammlungsgruppe basierend auf dem Status published
und dem Beitrag author
erstellt werden:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Returns `true` if the requested post is 'published'
// or the user authored the post
function authorOrPublished() {
return resource.data.published == true || request.auth.uid == resource.data.author;
}
match /{path=**}/posts/{post} {
// Anyone can query published posts
// Authors can query their unpublished posts
allow list: if authorOrPublished();
// Anyone can retrieve a published post
// Authors can retrieve an unpublished post
allow get: if authorOrPublished();
}
match /forums/{forumid}/posts/{postid} {
// Only a post's author can write to a post
allow write: if request.auth.uid == resource.data.author;
}
}
}
Mit diesen Regeln können Web-, Apple- und Android-Clients die folgenden Abfragen durchführen:
Jeder kann veröffentlichte Beiträge in einem Forum abrufen:
db.collection("forums/technology/posts").where('published', '==', true).get()
Alle veröffentlichten Beiträge eines Autors können in allen Foren abgerufen werden:
db.collectionGroup("posts").where("author", "==", "some_auth_id").where('published', '==', true).get()
Autoren können alle veröffentlichten und unveröffentlichten Beiträge in allen Foren abrufen:
var user = firebase.auth().currentUser; db.collectionGroup("posts").where("author", "==", user.uid).get()
Dokumente basierend auf Sammlungsgruppe und Dokumentpfad schützen und abfragen
In einigen Fällen ist es sinnvoll, Sammlungsgruppenabfragen basierend auf dem Dokumentpfad einzuschränken. Das Erstellen dieser Einschränkungen funktioniert genauso wie das Schützen und Abfragen von Dokumenten anhand eines Feldes.
Betrachten wir eine Anwendung, die die Transaktionen jedes Nutzers auf mehreren Aktien- und Kryptowährungsbörsen verfolgt:
/users/{userid}/exchange/{exchangeid}/transactions/{transaction}
{
amount: 100,
exchange: 'some_exchange_name',
timestamp: April 1, 2019 at 12:00:00 PM UTC-7,
user: "some_auth_id",
}
Beachten Sie das Feld user
. Obwohl bekannt ist, welcher Nutzer ein transaction
-Dokument aus dem Pfad des Dokuments besitzt, wird diese Information in jedem transaction
-Dokument dupliziert, da zwei Aktionen möglich sind:
Sammlungsgruppenabfragen erstellen, die auf Dokumente mit einem bestimmten
/users/{userid}
im Dokumentpfad beschränkt sind. Beispiel:var user = firebase.auth().currentUser; // Return current user's last five transactions across all exchanges db.collectionGroup("transactions").where("user", "==", user).orderBy('timestamp').limit(5)
Diese Einschränkung für alle Abfragen in der Sammlungsgruppe
transactions
erzwingen, sodass ein Nutzer dietransaction
-Dokumente eines anderen Nutzers nicht abrufen kann.
Diese Einschränkung wird in unseren Sicherheitsregeln erzwungen und die Datenvalidierung für das Feld user
eingeschlossen:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{path=**}/transactions/{transaction} {
// Authenticated users can retrieve only their own transactions
allow read: if resource.data.user == request.auth.uid;
}
match /users/{userid}/exchange/{exchangeid}/transactions/{transaction} {
// Authenticated users can write to their own transactions subcollections
// Writes must populate the user field with the correct auth id
allow write: if userid == request.auth.uid && request.data.user == request.auth.uid
}
}
}
Tipp
- Ein detaillierteres Beispiel für die rollenbasierte Zugriffssteuerung finden Sie unter Datenzugriff für Nutzer und Gruppen sichern.
- Referenz zu Sicherheitsregeln lesen