Daten sicher abfragen

Diese Seite basiert auf den Konzepten in Structuring Sicherheitsregeln und Schreibbedingungen für Sicherheit Regeln zu erklären , wie Cloud - Firestor Sicherheitsregeln interact mit Abfragen. Es wird genauer untersucht, wie sich Sicherheitsregeln auf die Abfragen auswirken, die Sie schreiben können, und beschrieben, wie Sie sicherstellen können, dass Ihre Abfragen dieselben Einschränkungen wie Ihre Sicherheitsregeln verwenden. Diese Seite beschreibt auch , wie man schreiben Sicherheitsregeln Abfragen erlauben oder zu verweigern , basierend auf Abfrageeigenschaften wie limit und orderBy .

Regeln sind keine Filter

Bedenken Sie beim Schreiben von Abfragen zum Abrufen von Dokumenten, dass Sicherheitsregeln keine Filter sind – Abfragen sind alles oder nichts. Um Ihnen Zeit und Ressourcen zu sparen, wertet Cloud Firestore eine Abfrage anhand ihres potenziellen Resultsets anstelle der tatsächlichen Feldwerte für alle Ihre Dokumente aus. Wenn eine Abfrage möglicherweise Dokumente zurückgeben könnte, für die der Client keine Leseberechtigung hat, schlägt die gesamte Anforderung fehl.

Abfragen und Sicherheitsregeln

Wie die folgenden Beispiele zeigen, müssen Sie Ihre Abfragen so schreiben, dass sie den Einschränkungen Ihrer Sicherheitsregeln entsprechen.

Sichere und Abfrage von Dokumenten basierend auf auth.uid

Im folgenden Beispiel wird veranschaulicht, wie Sie eine Abfrage schreiben, um durch eine Sicherheitsregel geschützte Dokumente abzurufen. Betrachten wir eine Datenbank , die eine Sammlung von enthält story Dokumente:

/stories/{storyid}

{
  title: "A Great Story",
  content: "Once upon a time...",
  author: "some_auth_id",
  published: false
}

Neben den title und content Felder, wobei jedes Dokument speichert der author und published Felder für die Zugangskontrolle zu verwenden. Diese Beispiele gehen die App verwenden Firebase - author Authentifizierung des festlegen author Feld auf die UID des Benutzers, der das Dokument erstellt hat . Firebase Authentifizierung auffüllt auch die request.auth Variable in den Sicherheitsregeln.

Die folgende Sicherheitsregel verwendet die request.auth und resource.data Variablen für jede Lese- und Schreibzugriff beschränken story zu sein Autor:

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;
    }
  }
}

Nehmen wir an, dass Ihre App enthält eine Seite , die zeigt der Benutzer eine Liste der story dokumentiert , dass sie verfasst hat . Sie könnten erwarten, dass Sie die folgende Abfrage verwenden können, um diese Seite zu füllen. Diese Abfrage schlägt jedoch fehl, da sie nicht dieselben Einschränkungen wie Ihre Sicherheitsregeln enthält:

Ungültig: Abfrage Einschränkungen entsprechen Einschränkungen keine Sicherheitsregeln

// This query will fail
db.collection("stories").get()

Die Abfrage schlägt fehl , auch wenn der aktuelle Benutzer tatsächlich ist der Autor von jeder story Dokument. Der Grund für dieses Verhalten ist , dass , wenn Cloud - Firestor Ihre Sicherheitsregeln gelten es die Abfrage gegenüber der potenziellen Ergebnismenge ausgewertet wird , nicht mit den tatsächlichen Eigenschaften der Dokumente in Ihrer Datenbank. Wenn eine Abfrage möglicherweise Dokumente enthalten könnte , die Ihre Sicherheitsregeln verstoßen, wird die Abfrage fehlschlagen.

Im Gegensatz dazu gelingt die folgende Abfrage, weil es die gleiche Einschränkung für das beinhaltet author Feld wie die Sicherheitsregeln:

Gültig: Abfrage Einschränkungen entsprechen Sicherheitsregeln Einschränkungen

var user = firebase.auth().currentUser;

db.collection("stories").where("author", "==", user.uid).get()

Dokumente basierend auf einem Feld sichern und abfragen

Um die Interaktion zwischen Abfragen und Regeln zu demonstrieren, unter den Sicherheitsregeln Lesezugriff für die Erweiterungs - stories Sammlung jeden Benutzer zu ermöglichen , lesen story Dokumente , bei denen das published Feld gesetzt ist true .

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 nach veröffentlichten Seiten muss dieselben Einschränkungen enthalten wie die Sicherheitsregeln:

db.collection("stories").where("published", "==", true).get()

Die Abfrage Einschränkung .where("published", "==", true) garantiert , dass resource.data.published ist true für jedes Ergebnis. Daher erfüllt diese Abfrage die Sicherheitsregeln und darf Daten lesen.

in und array-contains-any Abfragen

Wenn eine Auswertung in oder array-contains-any query Klausel gegen eine ruleset wertet Wolke Firestor jeweils getrennt Vergleichswert. Jeder Vergleichswert muss die Sicherheitsregeleinschränkungen erfüllen. Zum Beispiel für die folgende Regel:

match /mydocuments/{doc} {
  allow read: if resource.data.x > 5;
}

Ungültig: Abfrage garantiert nicht , dass x > 5 für alle potentiellen Dokumente

// This query will fail
db.collection("mydocuments").where("x", "in", [1, 3, 6, 42, 99]).get()

Gültig: Abfrage garantiert , dass x > 5 für alle potentiellen Dokumente

db.collection("mydocuments").where("x", "in", [6, 42, 99, 105, 200]).get()

Auswerten von Einschränkungen bei Abfragen

Ihre Sicherheitsregeln können auch Abfragen basierend auf ihren Einschränkungen akzeptieren oder ablehnen. Die request.query Variable enthält die limit , offset und orderBy Eigenschaften einer Abfrage. Ihre Sicherheitsregeln können beispielsweise jede Abfrage ablehnen, die die maximale Anzahl der abgerufenen Dokumente nicht auf einen bestimmten Bereich beschränkt:

allow list: if request.query.limit <= 10;

Der folgende Regelsatz zeigt, wie Sicherheitsregeln geschrieben werden, die Einschränkungen für Abfragen auswerten. Dieses Beispiel erweitert die vorherigen stories Regeln mit den folgenden Änderungen:

  • Der Regelsatz trennt die Leseregel in Regeln für get und list .
  • Die get Regel schränkt den Abruf von einzelnen Dokumente zu öffentlichen Dokumenten oder Dokumenten der Benutzer verfasst.
  • Die list gilt die gleichen Einschränkungen wie get aber für Abfragen. Es überprüft auch das Abfragelimit und lehnt dann jede Abfrage ohne Limit oder mit einem Limit von mehr als 10 ab.
  • Der Regelsatz definiert eine authorOrPublished() Funktion zu vermeiden Code - Duplizierung.
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 sind Abfragen auf eine einzelne Sammlung beschränkt und rufen nur Ergebnisse aus dieser Sammlung ab. Mit Sammelgruppe Abfragen können Sie Ergebnisse aus einer Sammelgruppe abrufen , bestehend aus allen Sammlungen mit derselben ID. In diesem Abschnitt wird beschrieben, wie Sie Ihre Sammlungsgruppenabfragen mithilfe von Sicherheitsregeln schützen.

Dokumente basierend auf Sammlungsgruppen sichern und abfragen

In Ihren Sicherheitsregeln müssen Sie Sammlungsgruppenabfragen explizit zulassen, indem Sie eine Regel für die Sammlungsgruppe schreiben:

  1. Stellen Sie sicher , rules_version = '2'; ist die erste Zeile Ihres Regelsatzes. Sammlung Gruppenabfragen erfordern die neuen rekursiven Platzhalter {name=**} Verhalten der Sicherheitsregeln Version 2.
  2. Schreiben Sie eine Regel für Sie Sammelgruppe mit match /{path=**}/ [COLLECTION_ID] /{doc} Gruppe match /{path=**}/ [COLLECTION_ID] /{doc} .

Betrachten wir zum Beispiel ein Forum in organisierte forum Dokumente , die posts Subkollektionen:

/foren/{forumid}/posts/{postid}

{
  author: "some_auth_id",
  authorname: "some_username",
  content: "I just read a great story.",
}

In dieser Anwendung machen wir Beiträge von ihren Eigentümern bearbeitbar und von authentifizierten Benutzern lesbar:

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 Benutzer kann die Beiträge jedes einzelnen Forums abrufen:

db.collection("forums/technology/posts").get()

Aber was ist, wenn Sie dem aktuellen Benutzer seine Beiträge in allen Foren anzeigen möchten? Sie können eine verwenden Sammelgruppe Abfrage abzurufen Ergebnisse aller posts Sammlungen:

var user = firebase.auth().currentUser;

db.collectionGroup("posts").where("author", "==", user.uid).get()

In der Sicherheitsregeln, müssen Sie diese Abfrage ermöglichen durch eine Lese- oder Listenregel für die Schreib posts Sammelgruppe:

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 für alle Sammlungen mit ID gilt posts , unabhängig von Hierarchie. Zum Beispiel gelten diese Regeln für alle folgenden posts Sammlungen:

  • /posts/{postid}
  • /forums/{forumid}/posts/{postid}
  • /forums/{forumid}/subforum/{subforumid}/posts/{postid}

Sichere Sammlungsgruppenabfragen basierend auf einem Feld

Wie Abfragen für einzelne Sammlungen müssen auch Abfragen für Sammlungsgruppen die von Ihren Sicherheitsregeln festgelegten Einschränkungen erfüllen. Zum Beispiel können wir hinzufügen , published Feld zu jedem Forum posten , wie wir in der tat stories Beispiel oben:

/foren/{forumid}/posts/{postid}

{
  author: "some_auth_id",
  authorname: "some_username",
  content: "I just read a great story.",
  published: false
}

Wir können dann schreiben Regeln für die posts Sammelgruppe auf der Basis published Status und der Post author :

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-, iOS- 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()
    
  • Jeder kann die veröffentlichten Beiträge eines Autors in allen Foren abrufen:

    db.collectionGroup("posts").where("author", "==", "some_auth_id").where('published', '==', true).get()
    
  • Autoren können alle ihre veröffentlichten und unveröffentlichten Beiträge in allen Foren abrufen:

    var user = firebase.auth().currentUser;
    
    db.collectionGroup("posts").where("author", "==", user.uid).get()
    

Sichern und Abfragen von Dokumenten basierend auf Sammlungsgruppe und Dokumentpfad

In einigen Fällen möchten Sie möglicherweise Sammlungsgruppenabfragen basierend auf dem Dokumentpfad einschränken. Um diese Einschränkungen zu erstellen, können Sie dieselben Techniken zum Sichern und Abfragen von Dokumenten basierend auf einem Feld verwenden.

Stellen Sie sich eine Anwendung vor, die die Transaktionen jedes Benutzers zwischen 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 user Auch wenn wir wissen , welche Benutzer ein besitzt transaction Dokument aus dem Pfad des Dokuments, wir diese Informationen in jedem Duplikat transaction Dokument , weil es uns ermöglicht es, zwei Dinge zu tun:

  • Schreibsammelgruppe Abfragen , die auf Dokumente beschränkt werden , die einen bestimmten umfassen /users/{userid} in ihrem Dokumentpfad. Beispielsweise:

    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)
    
  • Erzwingen diese Einschränkung für alle Abfragen auf der transactions Sammelgruppe so ein Benutzer einen anderen Benutzer nicht abrufen können , transaction

Wir setzen diese Einschränkung in unseren Sicherheitsregeln und umfassen Datenvalidierung für das user

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
    }
  }
}

Nächste Schritte