Schreibbedingungen für Sicherheitsregeln

Dieser Leitfaden baut auf dem Leitfaden Sicherheitsregeln strukturieren auf. Sie erfahren hier, wie Sie Ihren Firestore-Sicherheitsregeln Bedingungen hinzufügen. Wenn Sie mit den Grundlagen der Firestore-Sicherheitsregeln noch nicht vertraut sind, finden Sie entsprechende Informationen unter Erste Schritte mit Sicherheitsregeln.

Der wichtigste Baustein der Firestore-Sicherheitsregeln ist die Bedingung. Eine Bedingung ist ein boolescher Ausdruck, der festlegt, ob ein bestimmter Vorgang zulässig oder nicht zulässig ist. Mit Sicherheitsregeln können Sie Bedingungen schreiben, die die Nutzerauthentifizierung und eingehende Daten prüfen oder auch auf andere Bereiche Ihrer Datenbank zugreifen.

Authentication

Eines der am häufigsten verwendeten Sicherheitsregelmuster steuert den Zugriff auf Basis des Authentifizierungsstatus des Nutzers. So kann beispielsweise ermöglicht werden, dass nur angemeldete Nutzer Daten schreiben dürfen:

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 häufig verwendetes Muster dient dazu, dass Nutzer 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 Anwendung Firebase Authentication 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 Anwendungen speichern Informationen zur Zugriffssteuerung als Felder in Dokumenten der Datenbank. Mit Firestore-Sicherheitsregeln kann anhand von Dokumentdaten dynamisch festgelegt werden, wann Zugriffe zugelassen und wann sie abgelehnt werden:

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 Variable resource verweist auf das angeforderte Dokument und resource.data ist eine Zuordnung aller Felder und Werte, die im Dokument gespeichert sind. Weitere Informationen zur Variable resource finden Sie in der Referenzdokumentation.

Beim Schreiben von Daten möchten Sie möglicherweise eingehende Daten mit vorhandenen Daten vergleichen. In diesem Fall enthält die Variable request.resource den zukünftigen Status des Dokuments, wenn Ihr Regelsatz den ausstehenden Schreibvorgang zulässt. Bei update-Vorgängen, die nur einen Teil der Dokumentfelder ändern, enthält die Variable request.resource den Status des ausstehenden Dokuments nach dem Vorgang. Sie können die Feldwerte in request.resource prüfen, um unerwünschte oder inkonsistente Datenaktualisierungen zu vermeiden:

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

Auf andere Dokumente zugreifen

Mit den Funktionen get() und exists() können Ihre Sicherheitsregeln eingehende Anfragen anhand anderer Dokumente in der Datenbank auswerten. Die Funktionen get() und exists() erwarten 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 ausschließen.

Im Beispiel unten wird die Variable database von der 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
    }
  }
}

Bei Schreibvorgängen können Sie die Funktion getAfter() verwenden, um nach dem Abschluss einer Transaktion oder eines Batches von Schreibvorgängen aber vor dem Transaktion. oder dem Batch-Commit auf den Status eines Dokuments zuzugreifen. Wie bei get() wird für die getAfter()-Funktion ein vollständig angegebener Dokumentpfad verwendet. Sie können getAfter() verwenden, um Sätze von Schreibvorgängen zu definieren, die gemeinsam als Transaktion oder Batch ausgeführt werden müssen.

Limits für Zugriffsaufrufe

Die Anzahl der Zugriffe auf Dokumente ist je nach Regelsatzbewertung begrenzt:

  • 10 für Einzeldokumentanfragen und Abfrage-Anfragen.
  • 20 für Lesevorgänge, Transaktionen und Batch-Schreibvorgänge für mehrere Dokumente. Das vorherige Limit von 10 gilt auch für jede Operation.

    Angenommen beispielsweise, Sie erstellen eine Batch-Schreibanfrage mit 3 Schreiboperationen und Ihre Sicherheitsregeln verwenden 2 Dokumentzugriffsaufrufe, um jeden Schreibvorgang zu validieren. In diesem Fall verwendet jeder Schreibvorgang 2 von seinen 10 Zugriffsaufrufen und die Batch-Schreibanfrage 6 von ihren 20 Zugriffsaufrufen.

Das Überschreiten eines dieser Limits führt zu einem Fehler mit Berechtigungsverweigerung. Einige Dokumentzugriffsaufrufe können zwischengespeichert werden. Zwischengespeicherte Aufrufe werden nicht in die begrenzte Anzahl einberechnet.

Eine ausführliche Erläuterung dazu, wie sich diese Beschränkungen auf Transaktionen und Batch-Schreibvorgänge auswirken, finden Sie in der Übersicht zu Atomare Vorgänge sichern.

Zugriffsaufrufe und Preise

Mit diesen Funktionen wird ein Lesevorgang in Ihrer Datenbank ausgeführt. Das bedeutet, dass Ihnen auch dann Lesevorgänge in Rechnung gestellt werden, wenn Ihre Regeln die Anfrage ablehnen. Ausführliche Informationen finden Sie unter Firestore-Preise.

Benutzerdefinierte Funktionen

Wenn Ihre Sicherheitsregeln komplexer werden, können Sie Gruppen von Bedingungen in Funktionen verpacken, die Sie in Ihrem Regelsatz wiederverwenden können. Sicherheitsregeln unterstützen benutzerdefinierte Funktionen. Die Syntax für benutzerdefinierte Funktionen ähnelt in etwa JavaScript, die Funktionen für Sicherheitsregeln sind jedoch in einer domainspezifischen Sprache geschrieben, die einige wichtige Einschränkungen aufweist:

  • Funktionen können nur eine einzige return-Anweisung enthalten. Es ist keine zusätzliche Logik möglich. Beispielsweise können damit keine Schleifen ausgeführt und keine externen Dienste aufgerufen werden.
  • Funktionen bieten die Möglichkeit, automatisch auf Funktionen und Variablen aus dem Bereich zuzugreifen, in dem sie definiert sind. Beispiel: Eine Funktion, die im Bereich service cloud.firestore definiert ist, hat Zugriff auf die resource-Variable sowie auf integrierte Funktionen wie get() und exists().
  • Funktionen können andere Funktionen aufrufen, werden jedoch möglicherweise nicht rekursiv. Die Tiefe des Aufrufstapels ist auf 10 begrenzt.
  • In der Regelversion v2 können Funktionen Variablen mithilfe des Schlüsselworts let definieren. Für Funktionen sind bis zu 10 LET-Bindungen zulässig. Diese müssen aber mit einer Rückgabeanweisung enden.

Eine Funktion wird mit dem Keyword function definiert und benötigt null oder mehr Argumente. Beispielsweise können Sie die beiden in den obigen Beispielen verwendeten Bedingungsarten 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();
    }
  }
}

Die Verwendung von Funktionen in Ihren Sicherheitsregeln sorgt dafür, dass sie besser gepflegt werden können, da die Komplexität Ihrer Regeln zunimmt.

Regeln sind keine Filter

Wenn Sie Ihre Daten gesichert haben und mit dem Schreiben von Abfragen beginnen, müssen Sie beachten, dass Sicherheitsregeln keine Filter sind. Da Abfragen für alle Dokumente in einer Sammlung geschrieben werden, gibt Firestore potenziell nicht nur die Dokumente zurück, auf die der aktuelle Client Zugriff hat.

Ein Beispiel ist 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';
    }
  }
}

Abgelehnt (Denied): Diese Regel lehnt die folgende Abfrage ab, da die Ergebnismenge Dokumente enthalten kann, in denen visibility nicht public ist:

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

Zugelassen (Allowed): Diese Regel lässt die folgende Abfrage zu, weil die where("visibility", "==", "public")-Klausel garantiert, dass die Ergebnismenge die Bedingung der Regel erfüllt:

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

Firestore-Sicherheitsregeln werten jede Abfrage anhand ihres potenziellen Ergebnisses aus. Die Anfrage schlägt fehl, wenn ein Dokument zurückgegeben werden müsste, für das der Client keine Leseberechtigung hat. Abfragen müssen den durch Ihre Sicherheitsregeln festgelegten Beschränkungen entsprechen. Weitere Informationen zu Sicherheitsregeln und Abfragen finden Sie unter Daten sicher abfragen.

Weitere Informationen