Structurer les règles de sécurité Cloud Firestore

Cloud Firestore Security Rules vous permet de contrôler l'accès aux documents et dans votre base de données. La syntaxe des règles flexibles vous permet de créer des règles qui correspondent à toutes sortes d'éléments : toutes les écritures de l'intégralité de la base de données, ou bien les opérations sur un document spécifique.

Ce guide décrit la syntaxe et la structure de base des règles de sécurité. Combinez cette syntaxe aux conditions des règles de sécurité pour créer des ensembles de règles complets.

Déclaration de service et de base de données

Les éléments Cloud Firestore Security Rules commencent toujours par la déclaration suivante:

service cloud.firestore {
  match /databases/{database}/documents {
    // ...
  }
}

La déclaration service cloud.firestore définit la portée des règles pour Cloud Firestore, ce qui évite les conflits entre Cloud Firestore Security Rules et pour d'autres produits tels que Cloud Storage.

La déclaration match /databases/{database}/documents spécifie que les règles doivent correspondre à n'importe quelle base de données Cloud Firestore dans le projet. Actuellement, chaque projet ne comporte qu'une seule base de données nommée (default).

Règles de base pour les lectures et les écritures

Les règles de base comprennent une instruction match spécifiant un chemin de document et une expression allow détaillant la lecture des données spécifiées :

service cloud.firestore {
  match /databases/{database}/documents {

    // Match any document in the 'cities' collection
    match /cities/{city} {
      allow read: if <condition>;
      allow write: if <condition>;
    }
  }
}

Toutes les instructions de correspondance doivent pointer vers des documents, et non vers des collections. Une instruction de correspondance peut pointer vers un document spécifique, comme dans match /cities/SF, ou utiliser des caractères génériques pour pointer vers un document du chemin spécifié, comme dans match /cities/{city}.

Dans l'exemple ci-dessus, l'instruction de correspondance utilise la syntaxe de caractère générique {city}. Cela signifie que la règle s'applique à tous les documents de la collection cities, tels que /cities/SF ou /cities/NYC. Lorsque les expressions allow dans l'instruction de correspondance sont évaluées, la résolution de la variable city donne le nom de document de ville, tel que SF ou NYC.

Opérations précises

Dans certains cas, il est utile de décomposer les opérations read et write en opérations plus précises. Par exemple, votre application peut vouloir appliquer des conditions différentes à la création de documents et à la suppression de documents. Vous pouvez également autoriser les lectures de documents uniques, mais refuser les requêtes volumineuses.

Une règle read peut être divisée en get et list, tandis qu'une règle write peut être divisée en create, update et delete :

service cloud.firestore {
  match /databases/{database}/documents {
    // A read rule can be divided into get and list rules
    match /cities/{city} {
      // Applies to single document read requests
      allow get: if <condition>;

      // Applies to queries and collection read requests
      allow list: if <condition>;
    }

    // A write rule can be divided into create, update, and delete rules
    match /cities/{city} {
      // Applies to writes to nonexistent documents
      allow create: if <condition>;

      // Applies to writes to existing documents
      allow update: if <condition>;

      // Applies to delete operations
      allow delete: if <condition>;
    }
  }
}

Données hiérarchisées

Les données de Cloud Firestore sont organisées en collections de documents, et chaque document peut étendre la hiérarchie via des sous-collections. Il est important de comprendre comment les règles de sécurité interagissent avec les données hiérarchisées.

Examinons la situation dans laquelle chaque document de la collection cities contient une sous-collection landmarks. Les règles de sécurité ne s'appliquent qu'au chemin correspondant. Par conséquent, les contrôles d'accès définis dans la collection cities ne s'appliquent pas à la sous-collection landmarks. À la place, écrivez des règles explicites pour contrôler l'accès aux sous-collections :

service cloud.firestore {
  match /databases/{database}/documents {
    match /cities/{city} {
      allow read, write: if <condition>;

        // Explicitly define rules for the 'landmarks' subcollection
        match /landmarks/{landmark} {
          allow read, write: if <condition>;
        }
    }
  }
}

Lors de l'imbrication des instructions match, le chemin de l'instruction interne match est toujours relatif au chemin de l'instruction externe match. Les ensembles de règles suivants sont donc équivalents :

service cloud.firestore {
  match /databases/{database}/documents {
    match /cities/{city} {
      match /landmarks/{landmark} {
        allow read, write: if <condition>;
      }
    }
  }
}
service cloud.firestore {
  match /databases/{database}/documents {
    match /cities/{city}/landmarks/{landmark} {
      allow read, write: if <condition>;
    }
  }
}

Caractères génériques récursifs

Si vous souhaitez que les règles s'appliquent à une hiérarchie arbitrairement profonde, utilisez la syntaxe de caractères génériques récursifs, {name=**}. Exemple :

service cloud.firestore {
  match /databases/{database}/documents {
    // Matches any document in the cities collection as well as any document
    // in a subcollection.
    match /cities/{document=**} {
      allow read, write: if <condition>;
    }
  }
}

Lorsque vous utilisez la syntaxe de caractères génériques récursifs, la variable générique contient l'intégralité du segment de chemin correspondant, même si le document se trouve dans une sous-collection profondément imbriquée. Par exemple, les règles répertoriées ci-dessus correspondent à un document situé à l'adresse /cities/SF/landmarks/coit_tower et la valeur de la variable document sera SF/landmarks/coit_tower.

Notez toutefois que le comportement des caractères génériques récursifs dépend de la version des règles.

Version 1

Les règles de sécurité utilisent la version 1 par défaut. Dans la version 1, les caractères génériques récursifs correspondent à un ou plusieurs éléments de chemin. Ils ne correspondent pas à un chemin vide, match /cities/{city}/{document=**} correspond donc aux documents des sous-collections, mais pas dans la collection cities alors que match /cities/{document=**} correspond aux documents de la collection cities et des sous-collections.

Les caractères génériques récursifs doivent apparaître à la fin d'une instruction de correspondance.

Version 2

Dans la version 2 des règles de sécurité, les caractères génériques récursifs peuvent correspondre à zéro, un ou plusieurs éléments de chemin. match/cities/{city}/{document=**} correspond aux documents des sous-collections, ainsi qu'aux documents de la collection cities.

Vous devez activer la version 2 en ajoutant rules_version = '2'; en haut de vos règles de sécurité :

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    // Matches any document in the cities collection as well as any document
    // in a subcollection.
    match /cities/{city}/{document=**} {
      allow read, write: if <condition>;
    }
  }
}

Vous pouvez utiliser au maximum un caractère générique récursif par requête, mais dans la version 2, vous pouvez placer ce caractère générique n'importe où dans l'instruction de correspondance. Exemple :

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    // Matches any document in the songs collection group
    match /{path=**}/songs/{song} {
      allow read, write: if <condition>;
    }
  }
}

Si vous utilisez des requêtes de groupes de collections, vous devez utiliser la version 2. Consultez la page Sécuriser les requêtes de groupes de collections.

Chevauchement d'instructions de correspondance

Il est possible qu'un document corresponde à plusieurs instructions match. Dans le cas où plusieurs expressions allow correspondent à une requête, l'accès est autorisé si au moins une des conditions est définie sur true :

service cloud.firestore {
  match /databases/{database}/documents {
    // Matches any document in the 'cities' collection.
    match /cities/{city} {
      allow read, write: if false;
    }

    // Matches any document in the 'cities' collection or subcollections.
    match /cities/{document=**} {
      allow read, write: if true;
    }
  }
}

Dans l'exemple ci-dessus, toutes les lectures et écritures dans la collection cities seront autorisées, car la seconde règle est toujours true, même si la première règle est toujours false.

Limites des règles de sécurité

Lorsque vous utilisez des règles de sécurité, tenez compte des limites suivantes :

Limite Détails
Nombre maximal d'appels de méthode exists(), get() et getAfter() par requête
  • 10 pour les requêtes de documents uniques et les requêtes de type "query".
  • 20 pour les lectures de plusieurs documents, les transactions et les écritures par lot. La limite de 10 précédente s'applique également à chaque opération.

    Par exemple, imaginons que vous créez une requête d'écriture par lot comprenant trois opérations, et que vos règles de sécurité utilisent deux appels d'accès au document pour valider chaque écriture. Dans ce cas, chaque écriture utilise deux de ses 10 appels d'accès et la requête d'écriture par lot utilise six de ses 20 appels d'accès.

Le dépassement de l'une ou l'autre limite entraîne une erreur de type "permission refusée".

Certains appels d'accès aux documents peuvent être mis en cache, et les appels en cache ne sont pas pris en compte dans les limites.

Profondeur maximale d'instructions match imbriquées 10
Longueur maximale du chemin, en segments de chemin, autorisée dans un ensemble d'instructions match imbriquées 100
Nombre maximal de variables de capture de chemin autorisées dans un ensemble d'instructions match imbriquées 20
Profondeur maximale des appels de fonction 20
Nombre maximal d'arguments de fonction 7
Nombre maximal de liaisons de variables let par fonction 10
Nombre maximal d'appels de fonction récursifs ou cycliques 0 (non autorisé)
Nombre maximal d'expressions évaluées par requête 1 000
Taille maximale d'un ensemble de règles Les ensembles de règles doivent respecter deux limites de taille :
  • une limite de 256 Ko pour la taille du texte source de l'ensemble de règles ; publiée à partir de la console Firebase ou de la CLI en utilisant firebase deploy
  • une limite de 250 Ko applicable à la taille de l'ensemble de règles compilé qui apparaît lorsque Firebase traite la source et l'active sur le backend.

Étapes suivantes