了解 2023 年 Google I/O 大会上介绍的 Firebase 亮点。了解详情

Verwenden Sie die Bedingungen in den Firebase Cloud Storage-Sicherheitsregeln

Dieser Leitfaden baut auf dem Erlernen der Kernsyntax des Sprachleitfadens zu Firebase-Sicherheitsregeln auf, um zu zeigen, wie Sie Bedingungen zu Ihren Firebase-Sicherheitsregeln für Cloud Storage hinzufügen.

Der primäre Baustein der Cloud Storage-Sicherheitsregeln ist die Bedingung . Eine Bedingung ist ein boolescher Ausdruck, der festlegt, ob eine bestimmte Operation zugelassen oder verweigert werden soll. Für grundlegende Regeln funktioniert die Verwendung von true und false Literalen als Bedingungen sehr gut. Aber die Firebase Security Rules for Cloud Storage-Sprache bietet Ihnen Möglichkeiten, komplexere Bedingungen zu schreiben, die Folgendes können:

  • Überprüfen Sie die Benutzerauthentifizierung
  • Validieren Sie eingehende Daten

Authentifizierung

Firebase-Sicherheitsregeln für Cloud Storage lassen sich in die Firebase-Authentifizierung integrieren, um eine leistungsstarke benutzerbasierte Authentifizierung für Cloud Storage bereitzustellen. Dies ermöglicht eine granulare Zugriffskontrolle basierend auf Ansprüchen eines Firebase-Authentifizierungstokens.

Wenn ein authentifizierter Benutzer eine Anfrage an Cloud Storage durchführt, wird die Variable request.auth mit der uid des Benutzers ( request.auth.uid ) sowie den Ansprüchen des Firebase-Authentifizierungs-JWT ( request.auth.token ) gefüllt.

Darüber hinaus werden bei Verwendung der benutzerdefinierten Authentifizierung zusätzliche Ansprüche im Feld request.auth.token angezeigt.

Wenn ein nicht authentifizierter Benutzer eine Anfrage ausführt, ist die Variable request.auth null .

Unter Verwendung dieser Daten gibt es mehrere gängige Möglichkeiten, die Authentifizierung zum Sichern von Dateien zu verwenden:

  • Öffentlich: request.auth ignorieren
  • Authentifiziert privat: Stellen Sie sicher, dass request.auth nicht null ist
  • Benutzer privat: Überprüfen Sie, ob request.auth.uid einer Pfad- uid entspricht
  • Gruppe privat: Überprüfen Sie die Ansprüche des benutzerdefinierten Tokens auf Übereinstimmung mit einem ausgewählten Anspruch, oder lesen Sie die Metadaten der Datei, um festzustellen, ob ein Metadatenfeld vorhanden ist

Öffentlich

Jede Regel, die den Kontext request.auth nicht berücksichtigt, kann als public Regel betrachtet werden, da sie den Authentifizierungskontext des Benutzers nicht berücksichtigt. Diese Regeln können nützlich sein, um öffentliche Daten wie Spielinhalte, Sounddateien oder andere statische Inhalte anzuzeigen.

// Anyone to read a public image if the file is less than 100kB
// Anyone can upload a public file ending in '.txt'
match /public/{imageId} {
  allow read: if resource.size < 100 * 1024;
  allow write: if imageId.matches(".*\\.txt");
}

Authentifiziert privat

In bestimmten Fällen möchten Sie möglicherweise, dass Daten von allen authentifizierten Benutzern Ihrer Anwendung angezeigt werden können, nicht jedoch von nicht authentifizierten Benutzern. Da die Variable request.auth für alle nicht authentifizierten Benutzer null ist, müssen Sie nur überprüfen, ob die Variable „ request.auth vorhanden ist, um eine Authentifizierung zu verlangen:

// Require authentication on all internal image reads
match /internal/{imageId} {
  allow read: if request.auth != null;
}

Benutzer privat

Der mit Abstand häufigste Anwendungsfall für request.auth wird darin bestehen, einzelnen Benutzern granulare Berechtigungen für ihre Dateien zu erteilen: vom Hochladen von Profilbildern bis zum Lesen privater Dokumente.

Da Dateien in Cloud Storage einen vollständigen "Pfad" zu der Datei haben, ist alles, was erforderlich ist, um eine Datei zu erstellen, die von einem Benutzer kontrolliert wird, eine eindeutige, den Benutzer identifizierende Information im Dateinamenpräfix (z. B. die uid des Benutzers), die überprüft werden kann wenn die Regel ausgewertet wird:

// Only a user can upload their profile picture, but anyone can view it
match /users/{userId}/profilePicture.png {
  allow read;
  allow write: if request.auth.uid == userId;
}

Gruppe privat

Ein weiterer, ebenso häufiger Anwendungsfall besteht darin, Gruppenberechtigungen für ein Objekt zuzulassen, z. B. mehreren Teammitgliedern die Zusammenarbeit an einem freigegebenen Dokument zu ermöglichen. Dazu gibt es mehrere Ansätze:

  • Erstellen Sie ein benutzerdefiniertes Token für die Firebase-Authentifizierung, das zusätzliche Informationen über ein Gruppenmitglied enthält (z. B. eine Gruppen-ID).
  • Fügen Sie Gruppeninformationen (z. B. eine Gruppen-ID oder eine Liste autorisierter uid ) in die Dateimetadaten ein

Sobald diese Daten in den Token- oder Dateimetadaten gespeichert sind, kann innerhalb einer Regel darauf verwiesen werden:

// Allow reads if the group ID in your token matches the file metadata's `owner` property
// Allow writes if the group ID is in the user's custom token
match /files/{groupId}/{fileName} {
  allow read: if resource.metadata.owner == request.auth.token.groupId;
  allow write: if request.auth.token.groupId == groupId;
}

Bewertung anfordern

Uploads, Downloads, Metadatenänderungen und Löschungen werden anhand der an Cloud Storage gesendeten request ausgewertet. Zusätzlich zur eindeutigen ID des Benutzers und der Nutzlast der Firebase-Authentifizierung im Objekt request.auth , wie oben beschrieben, enthält die request den Dateipfad, in dem die Anfrage ausgeführt wird, die Uhrzeit, zu der die Anfrage empfangen wird, und den neuen resource if die Anforderung ist ein Schreiben.

Das request enthält auch die eindeutige ID des Benutzers und die Nutzdaten der Firebase-Authentifizierung im Objekt „ request.auth “, die im Abschnitt „Benutzerbasierte Sicherheit“ der Dokumentation näher erläutert werden.

Eine vollständige Liste der Eigenschaften im request ist unten verfügbar:

Eigentum Typ Beschreibung
auth map<Zeichenfolge, Zeichenfolge> Wenn ein Benutzer angemeldet ist, werden uid , die eindeutige ID des Benutzers, und token , eine Zuordnung von JWT-Ansprüchen für die Firebase-Authentifizierung, bereitgestellt. Andernfalls ist es null .
params map<Zeichenfolge, Zeichenfolge> Map mit den Abfrageparametern der Anfrage.
path Weg Ein path , der den Pfad darstellt, auf dem die Anforderung ausgeführt wird.
resource map<Zeichenfolge, Zeichenfolge> Der neue Ressourcenwert, der nur bei write vorhanden ist.
time Zeitstempel Ein Zeitstempel, der die Serverzeit darstellt, zu der die Anfrage ausgewertet wird.

Ressourcenbewertung

Beim Auswerten von Regeln möchten Sie möglicherweise auch die Metadaten der Datei auswerten, die hochgeladen, heruntergeladen, geändert oder gelöscht wird. Auf diese Weise können Sie komplexe und leistungsstarke Regeln erstellen, die beispielsweise das Hochladen von Dateien mit bestimmten Inhaltstypen zulassen oder nur das Löschen von Dateien, die eine bestimmte Größe überschreiten.

Firebase Security Rules for Cloud Storage stellt Dateimetadaten im resource bereit, das Schlüssel/Wert-Paare der Metadaten enthält, die in einem Cloud Storage-Objekt angezeigt werden. Diese Eigenschaften können bei read oder write überprüft werden, um die Datenintegrität sicherzustellen.

Bei write (z. B. Uploads, Aktualisierungen von Metadaten und Löschungen) haben Sie zusätzlich zum resource , das Dateimetadaten für die Datei enthält, die derzeit im Anforderungspfad vorhanden ist, auch die Möglichkeit, das Objekt request.resource zu verwenden. die eine Teilmenge der zu schreibenden Dateimetadaten enthält, wenn das Schreiben erlaubt ist. Sie können diese beiden Werte verwenden, um die Datenintegrität sicherzustellen oder Anwendungseinschränkungen wie Dateityp oder -größe durchzusetzen.

Eine vollständige Liste der Eigenschaften im resource ist unten verfügbar:

Eigentum Typ Beschreibung
name Schnur Der vollständige Name des Objekts
bucket Schnur Der Name des Buckets, in dem sich dieses Objekt befindet.
generation int Die Google Cloud Storage-Objektgenerierung dieses Objekts.
metageneration int Die Metagenerierung des Google Cloud Storage-Objekts dieses Objekts.
size int Die Größe des Objekts in Bytes.
timeCreated Zeitstempel Ein Zeitstempel, der die Zeit darstellt, zu der ein Objekt erstellt wurde.
updated Zeitstempel Ein Zeitstempel, der die Zeit darstellt, zu der ein Objekt zuletzt aktualisiert wurde.
md5Hash Schnur Ein MD5-Hash des Objekts.
crc32c Schnur Ein crc32c-Hash des Objekts.
etag Schnur Das diesem Objekt zugeordnete Etag.
contentDisposition Schnur Die Inhaltsdisposition, die diesem Objekt zugeordnet ist.
contentEncoding Schnur Die diesem Objekt zugeordnete Inhaltscodierung.
contentLanguage Schnur Die diesem Objekt zugeordnete Inhaltssprache.
contentType Schnur Der diesem Objekt zugeordnete Inhaltstyp.
metadata map<Zeichenfolge, Zeichenfolge> Schlüssel/Wert-Paare zusätzlicher, vom Entwickler angegebener benutzerdefinierter Metadaten.

request.resource enthält all diese mit Ausnahme von generation , metageneration , etag , timeCreated und updated .

Verbessern Sie mit Cloud Firestore

Sie können auf Dokumente in Cloud Firestore zugreifen, um andere Autorisierungskriterien zu bewerten.

Mithilfe der Funktionen firestore.get() und firestore.exists() können Ihre Sicherheitsregeln eingehende Anfragen anhand von Dokumenten in Cloud Firestore auswerten. Die Funktionen firestore.get() und firestore.exists() erwarten beide vollständig angegebene Dokumentpfade. Wenn Sie Variablen verwenden, um Pfade für firestore.get() und firestore.exists() zu erstellen, müssen Sie Variablen explizit mit der $(variable) -Syntax maskieren.

Im folgenden Beispiel sehen wir eine Regel, die den Lesezugriff auf Dateien auf die Benutzer beschränkt, die Mitglieder bestimmter Clubs sind.

service firebase.storage {
  match /b/{bucket}/o {
    match /users/{club}/files/{fileId} {
      allow read: if club in
        firestore.get(/databases/(default)/documents/users/$(request.auth.id)).memberships
    }
  }
}
Im nächsten Beispiel können nur die Freunde eines Benutzers ihre Fotos sehen.
service firebase.storage {
  match /b/{bucket}/o {
    match /users/{userId}/photos/{fileId} {
      allow read: if
        firestore.exists(/databases/(default)/documents/users/$(userId)/friends/$(request.auth.id))
    }
  }
}

Nachdem Sie Ihre ersten Cloud Storage-Sicherheitsregeln erstellt und gespeichert haben, die diese Cloud Firestore-Funktionen verwenden, werden Sie in der Firebase-Konsole oder der Firebase-Befehlszeilenschnittstelle aufgefordert, Berechtigungen zum Verbinden der beiden Produkte zu aktivieren.

Sie können die Funktion deaktivieren, indem Sie eine IAM-Rolle entfernen, wie unter Verwalten und Bereitstellen von Firebase-Sicherheitsregeln beschrieben.

Daten validieren

Firebase-Sicherheitsregeln für Cloud Storage können auch zur Datenvalidierung verwendet werden, einschließlich der Validierung von Dateinamen und -pfaden sowie Dateimetadateneigenschaften wie contentType und size .

service firebase.storage {
  match /b/{bucket}/o {
    match /images/{imageId} {
      // Only allow uploads of any image file that's less than 5MB
      allow write: if request.resource.size < 5 * 1024 * 1024
                   && request.resource.contentType.matches('image/.*');
    }
  }
}

Benutzerdefinierte Funktionen

Wenn Ihre Firebase-Sicherheitsregeln immer komplexer werden, möchten Sie möglicherweise Bedingungssätze in Funktionen verpacken, die Sie in Ihrem Regelsatz wiederverwenden können. Sicherheitsregeln unterstützen benutzerdefinierte Funktionen. Die Syntax für benutzerdefinierte Funktionen ähnelt ein wenig JavaScript, aber die Funktionen der Firebase-Sicherheitsregeln sind 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 Gültigkeitsbereich zugreifen, in dem sie definiert sind. Beispielsweise hat eine im Bereich service firebase.storage definierte Funktion Zugriff auf die resource und nur für Cloud Firestore auf integrierte Funktionen wie get() exists() .
  • Funktionen können andere Funktionen aufrufen, dürfen aber nicht rekursiv sein. Die gesamte Call-Stack-Tiefe ist auf 10 begrenzt.
  • In rules2 können Funktionen Variablen mit dem Schlüsselwort let definieren. Funktionen können beliebig viele Let-Bindungen haben, müssen aber 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 Arten von Bedingungen, die in den obigen Beispielen verwendet werden, in einer einzigen Funktion kombinieren:

service firebase.storage {
  match /b/{bucket}/o {
    // 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 /images/{imageId} {
      allow read, write: if signedInOrPublic();
    }
    match /mp3s/{mp3Ids} {
      allow read: if signedInOrPublic();
    }
  }
}

Die Verwendung von Funktionen in Ihren Firebase-Sicherheitsregeln macht sie wartungsfreundlicher, wenn die Komplexität Ihrer Regeln zunimmt.

Nächste Schritte

Nach dieser Erörterung der Bedingungen haben Sie ein differenzierteres Verständnis der Regeln und sind bereit:

Erfahren Sie, wie Sie mit Kernanwendungsfällen umgehen, und lernen Sie den Arbeitsablauf zum Entwickeln, Testen und Bereitstellen von Regeln kennen: