Règles de sécurité pour les opérations de pipeline

Bien que les opérations de pipeline offrent un large éventail de fonctionnalités, le moteur de règles est limité à la reconnaissance des filtres de comparaison (par exemple, >) et logiques (par exemple, or) pour garantir la satisfiabilité et la sécurité des contraintes.

Expressions de filtre acceptées

Pour que les opérations de pipeline soient limitées aux limites définies par vos règles, elles doivent utiliser des opérateurs logiques et de comparaison par rapport à des constantes. Les types de filtres suivants sont reconnus par le moteur de règles :

  • Comparaisons : eq, neq, gt, gte, lt, lte, in, arrayContains.
  • Logiques : and, or.

Voici quelques exemples :

  • where(eq("foo", 2))
  • where(lt("foo", 2))
  • documents("/user/1", "/user/2").where(...)

Propriétés de la requête

Vous pouvez continuer à utiliser l' request objet pour valider l'authentification et le contexte de la requête, bien que certaines propriétés disponibles dans les requêtes standards ne soient pas compatibles avec les opérations de pipeline.

Propriétés acceptées

Le nouveau moteur continue d'accepter les propriétés suivantes :

  • request.auth : accédez aux données d'UID et de jeton de l'utilisateur.
  • request.method : identifie l'opération (par exemple, get, list).
  • request.path : chemin d'accès à la ressource consultée.
  • request.time : horodatage côté serveur de la requête.

Propriétés non acceptées

Les propriétés request.query, telles que limit, offset et orderBy, ne sont pas acceptées pour les vérifications des règles des opérations de pipeline en raison de la complexité de la détermination de ces valeurs dans les requêtes en plusieurs étapes.

Gestion des étapes de pipeline et autorisations

Il existe différentes étapes de pipeline qui correspondent à des opérations granulaires spécifiques dans les règles de sécurité :

  • Autorisations allow list : déclenchées par les étapes collection(), collectionGroup() et database().
  • allow get autorisations : déclenchées par l'étape documents(), qui est traitée de la même manière qu'une opération get par lot.
  • Étape des littéraux : l'étape literals() ne lit pas les données de la base de données, mais peut entraîner des coûts. Pour éviter les abus, elle doit être associée à une autre étape (comme collection()) qui peut être vérifiée par des règles.

Étapes de modification des champs

Les règles ne fonctionnent que sur les données stockées et non sur les valeurs dérivées. Si un pipeline inclut des étapes qui modifient des champs (par exemple, add_fields(...), replace_with(...), select(...), remove_fields(...)), le moteur de règles cesse d'appliquer les contraintes de filtre une fois cette étape rencontrée. Pour vous assurer que les règles fonctionnent comme prévu, placez vos étapes de filtre (c'est-à-dire where) avant toutes les étapes susceptibles de modifier les documents stockés d'origine.

Prenons l'exemple de la règle de sécurité suivante :

match /databases/{database}/documents {
  match /cities/{city} {
    // Allow the user to read data if the document has the 'visibility'
    // field set to 'public'
    allow read: if resource.data.visibility == 'public';
  }
}

Refusé : cette règle rejette le pipeline suivant, car l'étape addFields se produit avant le filtrage des documents où visibility est public :

const results = await db.pipeline()
  .collection("/cities")
  // Filters after a modification stage are ignored by Rules.
  .addFields(constant(1000).as("population"))
  .where(eq(field("visibility"), constant("public")))
  .execute();

Autorisé : cette règle autorise le pipeline suivant, car l'étape where(eq(field("visibility"), constant("public"))) se produit avant toutes les étapes de modification :

const results = await db.pipeline()
  .collection("/cities")
  .where(eq(field("visibility"), constant("public")))
  .addFields(constant(1000).as("population"))
  .execute();