Bedingungen für Cloud Firestore-Sicherheitsregeln schreiben

Dieser Leitfaden baut auf dem Leitfaden zur Strukturierung von Sicherheitsregeln auf und zeigt, wie Sie Bedingungen zu Ihren Cloud Firestore-Sicherheitsregeln hinzufügen. Wenn Sie mit den Grundlagen der Cloud Firestore-Sicherheitsregeln nicht vertraut sind, lesen Sie die Anleitung „Erste Schritte“ .

Der Hauptbaustein der Cloud Firestore-Sicherheitsregeln ist die Bedingung. Eine Bedingung ist ein boolescher Ausdruck, der bestimmt, ob ein bestimmter Vorgang zugelassen oder verweigert werden soll. Verwenden Sie Sicherheitsregeln, um Bedingungen zu schreiben, die die Benutzerauthentifizierung überprüfen, eingehende Daten validieren oder sogar auf andere Teile Ihrer Datenbank zugreifen.

Authentifizierung

Eines der häufigsten Sicherheitsregelmuster ist die Zugriffskontrolle basierend auf dem Authentifizierungsstatus des Benutzers. Beispielsweise möchte Ihre App möglicherweise nur angemeldeten Benutzern das Schreiben von Daten erlauben:

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

Ein weiteres gängiges Muster besteht darin, sicherzustellen, dass Benutzer nur ihre eigenen Daten lesen und schreiben können:

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

Wenn Ihre App Firebase Authentication oder Google Cloud Identity Platform verwendet, enthält die Variable request.auth die Authentifizierungsinformationen für den Client, der Daten anfordert. Weitere Informationen zu request.auth finden Sie in der Referenzdokumentation .

Datenvalidierung

Viele Apps speichern Zugriffskontrollinformationen als Felder für Dokumente in der Datenbank. Cloud Firestore-Sicherheitsregeln können den Zugriff basierend auf Dokumentdaten dynamisch zulassen oder verweigern:

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

Die resource bezieht sich auf das angeforderte Dokument und resource.data ist eine Zuordnung aller im Dokument gespeicherten Felder und Werte. Weitere Informationen zur resource finden Sie in der Referenzdokumentation .

Beim Schreiben von Daten möchten Sie möglicherweise eingehende Daten mit vorhandenen Daten vergleichen. Wenn Ihr Regelsatz in diesem Fall das ausstehende Schreiben zulässt, enthält die Variable request.resource den zukünftigen Status des Dokuments. Bei update , die nur eine Teilmenge der Dokumentfelder ändern, enthält die Variable request.resource den ausstehenden Dokumentstatus nach dem Vorgang. Sie können die Feldwerte in request.resource überprüfen, um unerwünschte oder inkonsistente Datenaktualisierungen zu verhindern:

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

Greifen Sie auf andere Dokumente zu

Mit den Funktionen get() und exists() können Ihre Sicherheitsregeln eingehende Anfragen anhand anderer Dokumente in der Datenbank bewerten. Die Funktionen get() und exists() erwarten beide vollständig angegebene Dokumentpfade. Wenn Sie Variablen verwenden, um Pfade für get() und exists() zu erstellen, müssen Sie Variablen mithilfe der $(variable) -Syntax explizit maskieren.

Im folgenden Beispiel wird die database durch die Match-Anweisung match /databases/{database}/documents erfasst und zur Bildung des Pfads verwendet:

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

Für Schreibvorgänge können Sie die Funktion getAfter() verwenden, um auf den Status eines Dokuments zuzugreifen, nachdem eine Transaktion oder ein Stapel von Schreibvorgängen abgeschlossen ist, aber bevor die Transaktion oder der Stapel festgeschrieben wird. Wie get() benötigt die Funktion getAfter() einen vollständig angegebenen Dokumentpfad. Sie können getAfter() verwenden, um Schreibsätze zu definieren, die zusammen als Transaktion oder Stapel erfolgen müssen.

Zugriffslimits für Anrufe

Es gibt eine Begrenzung für Dokumentzugriffsaufrufe pro Regelsatzauswertung:

  • 10 für Einzeldokumentanfragen und Abfrageanfragen.
  • 20 für das Lesen mehrerer Dokumente, Transaktionen und Batch-Schreibvorgänge. Für jeden Vorgang gilt auch die bisherige Grenze von 10.

    Stellen Sie sich beispielsweise vor, Sie erstellen eine Batch-Schreibanforderung mit drei Schreibvorgängen und Ihre Sicherheitsregeln verwenden zwei Dokumentzugriffsaufrufe, um jeden Schreibvorgang zu validieren. In diesem Fall verwendet jeder Schreibvorgang zwei seiner 10 Zugriffsaufrufe und die gestapelte Schreibanforderung verwendet 6 seiner 20 Zugriffsaufrufe.

Das Überschreiten eines dieser Grenzwerte führt zu einem Fehler, bei dem die Berechtigung verweigert wurde. Einige Dokumentzugriffsaufrufe werden möglicherweise zwischengespeichert und zwischengespeicherte Aufrufe werden nicht auf die Grenzwerte angerechnet.

Eine ausführliche Erläuterung, wie sich diese Grenzwerte auf Transaktionen und Batch-Schreibvorgänge auswirken, finden Sie im Leitfaden zum Sichern atomarer Vorgänge .

Zugriff auf Anrufe und Preise

Durch die Verwendung dieser Funktionen wird ein Lesevorgang in Ihrer Datenbank ausgeführt, was bedeutet, dass Ihnen das Lesen von Dokumenten in Rechnung gestellt wird, auch wenn Ihre Regeln die Anforderung ablehnen. Genauere Rechnungsinformationen finden Sie unter Cloud Firestore-Preise .

Benutzerdefinierte Funktionen

Wenn Ihre Sicherheitsregeln komplexer werden, möchten Sie möglicherweise Bedingungssätze in Funktionen einbinden, die Sie in Ihrem Regelsatz wiederverwenden können. Sicherheitsregeln unterstützen benutzerdefinierte Funktionen. Die Syntax für benutzerdefinierte Funktionen ähnelt ein wenig der von JavaScript, Sicherheitsregelfunktionen sind jedoch in einer domänenspezifischen Sprache geschrieben, die einige wichtige Einschränkungen aufweist:

  • Funktionen können nur eine einzige return Anweisung enthalten. Sie dürfen keine zusätzliche Logik enthalten. Sie können beispielsweise keine Schleifen ausführen oder externe Dienste aufrufen.
  • Funktionen können automatisch auf Funktionen und Variablen aus dem Bereich zugreifen, in dem sie definiert sind. Beispielsweise hat eine im service cloud.firestore definierte Funktion Zugriff auf die resource und integrierte Funktionen wie get() und exists() .
  • Funktionen können andere Funktionen aufrufen, dürfen jedoch nicht rekursiv sein. Die Gesamttiefe des Aufrufstapels ist auf 10 begrenzt.
  • In der Regelversion v2 können Funktionen Variablen mithilfe des Schlüsselworts let definieren. Funktionen können bis zu 10 Let-Bindungen haben, müssen jedoch mit einer Return-Anweisung enden.

Eine Funktion wird mit dem Schlüsselwort function definiert und akzeptiert null oder mehr Argumente. Beispielsweise möchten Sie möglicherweise die beiden in den obigen Beispielen verwendeten Arten von Bedingungen in einer einzigen Funktion kombinieren:

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

Durch die Verwendung von Funktionen in Ihren Sicherheitsregeln werden diese bei zunehmender Komplexität Ihrer Regeln besser wartbar.

Regeln sind keine Filter

Wenn Sie Ihre Daten sichern und mit dem Schreiben von Abfragen beginnen, denken Sie daran, dass Sicherheitsregeln keine Filter sind. Sie können nicht eine Abfrage für alle Dokumente in einer Sammlung schreiben und erwarten, dass Cloud Firestore nur die Dokumente zurückgibt, auf die der aktuelle Client zugreifen darf.

Nehmen Sie zum Beispiel die folgende Sicherheitsregel:

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

Verweigert : Diese Regel lehnt die folgende Abfrage ab, da der Ergebnissatz Dokumente enthalten kann, deren visibility nicht public ist:

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

Zulässig : Diese Regel lässt die folgende Abfrage zu, da die Klausel where("visibility", "==", "public") garantiert, dass die Ergebnismenge die Bedingung der Regel erfüllt:

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

Cloud Firestore-Sicherheitsregeln bewerten jede Abfrage anhand ihres potenziellen Ergebnisses und schlagen die Anforderung fehl, wenn sie ein Dokument zurückgeben könnte, für das der Client keine Leseberechtigung hat. Abfragen müssen den durch Ihre Sicherheitsregeln festgelegten Einschränkungen folgen. Weitere Informationen zu Sicherheitsregeln und Abfragen finden Sie unter Daten sicher abfragen .

Nächste Schritte