Mit Firebase Realtime Database-Sicherheitsregeln können Sie den Zugriff auf gespeicherte Daten steuern in Ihrer Datenbank. Mit der flexiblen Regelsyntax können Sie Regeln, die mit beliebigen Daten übereinstimmen, von Schreibvorgängen in die Datenbank bis hin zu Vorgängen auf einzelnen Knoten.
Sicherheitsregeln für Realtime Database sind eine deklarative Konfiguration für Ihre Datenbank. Das bedeutet, dass die Regeln unabhängig von der Produktlogik definiert werden. Dieses hat eine Reihe von Vorteilen: Die Kunden sind nicht für die Durchsetzung von Sicherheitsvorkehrungen, Implementierungen, die Ihre Daten nicht gefährden. Es ist keine zwischengeschaltete eingeladene Person (z. B. Server) erforderlich, um die Daten zu schützen. aus der ganzen Welt.
In diesem Thema werden die grundlegende Syntax und Struktur von Realtime Database-Sicherheitsregeln beschrieben zum Erstellen vollständiger Regelsätze.
Sicherheitsregeln strukturieren
Realtime Database-Sicherheitsregeln bestehen aus JavaScript-ähnlichen Ausdrücken in einem JSON-Dokument. Die Struktur Ihrer Regeln sollte der Struktur der Daten, die Sie in Ihrer Datenbank gespeichert haben.
Grundlegende Regeln identifizieren eine Gruppe von Knoten, die gesichert werden sollen, die Zugriffsmethoden (z.B. Lese-,
Schreibvorgänge) und die Bedingungen, unter denen der Zugriff erlaubt oder verweigert wird.
In den folgenden Beispielen sind unsere Bedingungen einfache true
- und false
-Anweisungen. Im nächsten Thema werden wir jedoch dynamischere Möglichkeiten zur Ausdrucksweise von Bedingungen behandeln.
Wenn wir z. B. versuchen, eine child_node
unter einer parent_node
zu sichern,
lautet die allgemeine Syntax:
{ "rules": { "parent_node": { "child_node": { ".read": <condition>, ".write": <condition>, ".validate": <condition>, } } } }
Wenden wir dieses Muster an. Nehmen wir zum Beispiel an, Sie führen eine Liste mit folgenden Daten:
{ "messages": { "message0": { "content": "Hello", "timestamp": 1405704370369 }, "message1": { "content": "Goodbye", "timestamp": 1405704395231 }, ... } }
Ihre Regeln sollten in ähnlicher Weise strukturiert sein. Hier ist eine Reihe von die für diese Datenstruktur sinnvoll sind. Dieses Das Beispiel zeigt, wie wir Datenbankknoten angeben, für die Regeln gelten für die Auswertung von Regeln an diesen Knoten.
{ "rules": { // For requests to access the 'messages' node... "messages": { // ...and the individual wildcarded 'message' nodes beneath // (we'll cover wildcarding variables more a bit later).... "$message": { // For each message, allow a read operation if <condition>. In this // case, we specify our condition as "true", so read access is always granted. ".read": "true", // For read-only behavior, we specify that for write operations, our // condition is false. ".write": "false" } } } }
Grundlegende Regelvorgänge
Es gibt drei Arten von Regeln zum Erzwingen der Sicherheit je nach Art der
Vorgang, der für die Daten ausgeführt wird: .write
, .read
und .validate
. Hier eine kurze Zusammenfassung der Zwecke:
Regeltypen | |
---|---|
.read | Beschreibt, ob und wann Daten von Nutzern gelesen werden dürfen. |
.write | Hier wird beschrieben, ob und wann Daten geschrieben werden dürfen. |
.valid | Definiert, wie ein richtig formatierter Wert aussieht, ob er untergeordnete Attribute hat, und den Datentyp. |
Platzhaltererfassungsvariablen
Alle Regeln verweisen auf Knoten. Eine Anweisung kann auf eine bestimmte
Knoten oder verwenden Sie $
-Platzhalter für Erfassungsvariablen, um auf Knotensätze bei einem bestimmten
Ebene der Hierarchie. Verwenden Sie diese Erfassungsvariablen, um den Wert des Knotens zu speichern
Schlüssel zur Verwendung in nachfolgenden Regelanweisungen. Mit dieser Methode können Sie komplexere Rules Bedingungen schreiben. Das wird im nächsten Thema genauer behandelt.
{ "rules": { "rooms": { // this rule applies to any child of /rooms/, the key for each room id // is stored inside $room_id variable for reference "$room_id": { "topic": { // the room's topic can be changed if the room id has "public" in it ".write": "$room_id.contains('public')" } } } } }
Die dynamischen $
-Variablen können auch parallel zu konstanten Pfadnamen verwendet werden. In diesem Beispiel wird die Variable $other
verwendet, um eine .validate
-Regel zu deklarieren, die dafür sorgt, dass widget
keine anderen untergeordneten Elemente als title
und color
hat.
Jeder Schreibvorgang, der zur Erstellung zusätzlicher untergeordneter Elemente führen würde, würde fehlschlagen.
{ "rules": { "widget": { // a widget can have a title or color attribute "title": { ".validate": true }, "color": { ".validate": true }, // but no other child paths are allowed // in this case, $other means any key excluding "title" and "color" "$other": { ".validate": false } } } }
kaskadierende Lese- und Schreibregeln
.read
- und .write
-Regeln werden von oben nach unten angewendet. Dabei werden Regeln mit niedrigerer Priorität von Regeln mit höherer Priorität überschrieben. Wenn eine Regel Lese- oder Schreibberechtigungen für einen bestimmten Pfad gewährt, wird auch Zugriff auf alle untergeordneten Knoten gewährt. Betrachten Sie die folgende Struktur:
{ "rules": { "foo": { // allows read to /foo/* ".read": "data.child('baz').val() === true", "bar": { /* ignored, since read was allowed already */ ".read": false } } } }
Durch diese Sicherheitsstruktur kann /bar/
jederzeit gelesen werden, wenn
/foo/
enthält eine untergeordnete baz
mit dem Wert true
.
Die Regel ".read": false
unter /foo/bar/
hat hier keine Auswirkungen, da der Zugriff nicht über einen untergeordneten Pfad widerrufen werden kann.
Auch wenn es nicht sofort intuitiv erscheint, ist dies ein wichtiger Teil der Regelsprache und ermöglicht die Implementierung sehr komplexer Zugriffsrechte mit minimalem Aufwand. Das wird später in diesem Leitfaden anhand der nutzerbasierten Sicherheit veranschaulicht.
.validate
-Regeln werden nicht kaskadiert. Alle Validierungsregeln müssen auf allen Ebenen der Hierarchie erfüllt sein, damit ein Schreibvorgang zulässig ist.
Regeln sind keine Filter
Regeln werden atomar angewendet. Das bedeutet, dass ein Lese- oder Schreibvorgang sofort fehlschlägt, wenn an diesem oder einem übergeordneten Speicherort keine Regel vorhanden ist, die den Zugriff gewährt. Auch wenn alle betroffenen Kinderpfade zugänglich sind, wird das Lesen am übergeordneten Speicherort fehlschlagen. Betrachten Sie diese Struktur:
{ "rules": { "records": { "rec1": { ".read": true }, "rec2": { ".read": false } } } }
Wenn Sie nicht wissen, dass Regeln atomar ausgewertet werden, könnte es so aussehen, als würde beim Abrufen des Pfads /records/
rec1
zurückgegeben, aber nicht rec2
. Das eigentliche Ergebnis ist jedoch ein Fehler:
JavaScript
var db = firebase.database(); db.ref("records").once("value", function(snap) { // success method is not called }, function(err) { // error callback triggered with PERMISSION_DENIED });
Objective-C
FIRDatabaseReference *ref = [[FIRDatabase database] reference]; [[_ref child:@"records"] observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) { // success block is not called } withCancelBlock:^(NSError * _Nonnull error) { // cancel block triggered with PERMISSION_DENIED }];
Swift
var ref = FIRDatabase.database().reference() ref.child("records").observeSingleEventOfType(.Value, withBlock: { snapshot in // success block is not called }, withCancelBlock: { error in // cancel block triggered with PERMISSION_DENIED })
Java
FirebaseDatabase database = FirebaseDatabase.getInstance(); DatabaseReference ref = database.getReference("records"); ref.addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(DataSnapshot snapshot) { // success method is not called } @Override public void onCancelled(FirebaseError firebaseError) { // error callback triggered with PERMISSION_DENIED }); });
REST
curl https://docs-examples.firebaseio.com/rest/records/ # response returns a PERMISSION_DENIED error
Da der Lesevorgang bei /records/
atomar ist und es keine Leseregel gibt, die Zugriff auf alle Daten unter /records/
gewährt, wird ein PERMISSION_DENIED
-Fehler ausgegeben. Wenn wir diese Regel im Sicherheitssimulator in der Firebase-Konsole bewerten, sehen wir, dass der Lesevorgang abgelehnt wurde, weil keine Leseregel den Zugriff auf den Pfad /records/
erlaubte. Die Regel für rec1
nie bewertet, da er nicht im gewünschten Pfad lag. Abrufen
rec1
, müssten wir direkt darauf zugreifen:
JavaScript
var db = firebase.database(); db.ref("records/rec1").once("value", function(snap) { // SUCCESS! }, function(err) { // error callback is not called });
Objective-C
FIRDatabaseReference *ref = [[FIRDatabase database] reference]; [[ref child:@"records/rec1"] observeSingleEventOfType:FEventTypeValue withBlock:^(FIRDataSnapshot *snapshot) { // SUCCESS! }];
Swift
var ref = FIRDatabase.database().reference() ref.child("records/rec1").observeSingleEventOfType(.Value, withBlock: { snapshot in // SUCCESS! })
Java
FirebaseDatabase database = FirebaseDatabase.getInstance(); DatabaseReference ref = database.getReference("records/rec1"); ref.addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(DataSnapshot snapshot) { // SUCCESS! } @Override public void onCancelled(FirebaseError firebaseError) { // error callback is not called } });
REST
curl https://docs-examples.firebaseio.com/rest/records/rec1 # SUCCESS!
Überlappende Anweisungen
Es ist möglich, dass auf einen Knoten mehrere Regeln angewendet werden. Im
Wenn mehrere Regelausdrücke einen Knoten identifizieren, ist die Zugriffsmethode
abgelehnt, wenn eine der Bedingungen false
ist:
{ "rules": { "messages": { // A rule expression that applies to all nodes in the 'messages' node "$message": { ".read": "true", ".write": "true" }, // A second rule expression applying specifically to the 'message1` node "message1": { ".read": "false", ".write": "false" } } } }
Im obigen Beispiel sind Lesevorgänge im Knoten message1
abgelehnt, da die zweite Regel immer false
lautet, auch wenn die erste
ist immer true
.
Nächste Schritte
Weitere Informationen zu den Sicherheitsregeln der Firebase Realtime Database:
Das nächste wichtige Konzept der Rules-Sprache sind dynamische Bedingungen. Mit diesen können Sie unter anderem die Nutzerautorisierung prüfen, vorhandene und eingehende Daten vergleichen, eingehende Daten validieren und die Struktur von Abfragen vom Client prüfen.
Typische Sicherheitsanwendungsfälle und die entsprechenden Definitionen der Firebase-Sicherheitsregeln