Estructura reglas de seguridad de Cloud Firestore

Las Cloud Firestore Security Rules te permiten controlar el acceso a documentos y colecciones en tu base de datos. La sintaxis de reglas flexibles te permite crear reglas que coincidan con todo, desde todas las operaciones de escritura en la base de datos hasta las operaciones en un documento específico.

Esta guía describe la sintaxis básica y la estructura de las reglas de seguridad. Combina esta sintaxis con las condiciones de las reglas de seguridad para crear conjuntos de reglas completos.

Declaración del servicio y la base de datos

Cloud Firestore Security Rules siempre comienza con la siguiente declaración:

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

La declaración service cloud.firestore define el permiso de las reglas en Cloud Firestore, lo que evita conflictos entre Cloud Firestore Security Rules y las reglas de otros productos, como Cloud Storage.

La declaración match /databases/{database}/documents especifica que las reglas deberían coincidir con cualquier base de datos de Cloud Firestore en el proyecto. Actualmente, cada proyecto tiene solo una base de datos llamada (default).

Reglas básicas de lectura y escritura

Las reglas básicas consisten en una declaración match que especifica la ruta de un documento y una expresión allow que describe cuándo se permite la lectura de los datos especificados:

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

Todas las declaraciones de coincidencia deben apuntar a los documentos, no a las colecciones. Una declaración de coincidencia puede apuntar a un documento específico, como en match /cities/SF, o usar comodines para apuntar a cualquier documento en la ruta especificada, como en match /cities/{city}.

En el ejemplo anterior, la declaración de coincidencia usa la sintaxis de comodín {city}. Esto significa que la regla se aplica a cualquier documento de la colección cities, como /cities/SF o /cities/NYC. Cuando se evalúan las expresiones allow en la declaración de coincidencia, la variable city se convierte en el nombre del documento de la ciudad, como SF o NYC.

Operaciones detalladas

En algunas situaciones, es útil desglosar read y write en operaciones más detalladas. Por ejemplo, la app podría aplicar condiciones diferentes para crear documentos que para eliminarlos. También, podrías permitir lecturas de un solo documento, pero rechazar las consultas de mayor tamaño.

Una regla read se puede dividir en get y list, mientras que una regla write se puede dividir en create, update y 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>;
    }
  }
}

Datos jerárquicos

Los datos de Cloud Firestore se organizan en colecciones de documentos y cada documento puede extender la jerarquía a través de subcolecciones. Es importante comprender cómo interactúan las reglas de seguridad con los datos jerárquicos.

Considera la situación en la que cada documento de la colección cities contiene una subcolección landmarks. Las reglas de seguridad se aplican solo a la ruta que coincide, por lo que no se aplican los controles de acceso definidos de la colección cities a la subcolección landmarks. En cambio, debes escribir reglas explícitas para controlar el acceso a las subcolecciones:

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

Cuando se anidan declaraciones match, la ruta de la declaración match interna siempre está relacionada con la ruta de la declaración match externa. Por lo tanto, los siguientes conjuntos de reglas son equivalentes:

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

Comodines recurrentes

Si quieres usar reglas que se apliquen a una jerarquía de profundidad arbitraria, usa la sintaxis de comodines recurrentes, {name=**}. Por ejemplo:

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

Cuando uses esta sintaxis, los comodines disponibles contendrán el segmento de la ruta que coincide completo, incluso si el documento se ubica en una subcolección anidada a mayor profundidad. Por ejemplo, las reglas anteriores coincidirían con un documento ubicado en /cities/SF/landmarks/coit_tower y el valor de la variable document sería SF/landmarks/coit_tower.

Sin embargo, ten en cuenta que el comportamiento de los comodines recurrentes depende de la versión de las reglas.

Versión 1

Las reglas de seguridad usan la versión 1 de forma predeterminada. En la versión 1, los comodines recurrentes coinciden con uno o más elementos de ruta. No obstante, no pueden coincidir con una ruta vacía, por lo que match /cities/{city}/{document=**} coincide con los documentos de las subcolecciones, pero no con los de la colección cities, mientras que match /cities/{document=**} coincide con los documentos en la colección cities y sus subcolecciones.

Los comodines recurrentes deben aparecer al final de una declaración match.

Versión 2

En la versión 2 de las reglas de seguridad, los comodines recurrentes coinciden con cero o más elementos de ruta, por lo que match/cities/{city}/{document=**} coincide con los documentos de cualquier subcolección o colección de cities.

Para usar la versión 2, debes agregar rules_version = '2'; en la parte superior de tus reglas de seguridad:

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

Puedes tener, como máximo, un comodín recurrente por declaración match, pero, en la versión 2, puedes colocar este comodín en cualquier lugar de la declaración. Por ejemplo:

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

Debes usar la versión 2 si deseas usar las consultas de grupos de colecciones; consulta cómo proteger las consultas de grupos de colecciones.

Superposiciona declaraciones match

Es posible que un documento coincida con más de una declaración match. Si varias expresiones allow coinciden con una solicitud, se permite el acceso siempre que alguna de las condiciones sea 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;
    }
  }
}

En el ejemplo anterior, se permitirán todas las lecturas y escrituras en la colección cities, ya que la segunda regla siempre es true, incluso si la primera regla siempre es false.

Límites de las reglas de seguridad

Cuando trabajes con reglas de seguridad, ten en cuenta los siguientes límites:

Límite Detalles
Cantidad máxima de llamadas exists(), get() y getAfter() por solicitud
  • El límite es de 10 para las solicitudes de un solo documento o las solicitudes de consulta.
  • El límite es de 20 para las lecturas de varios documentos, transacciones y escrituras en lotes. El límite anterior de 10 también se aplica a cada operación.

    Por ejemplo, imagina que creas una solicitud de escritura en lotes con 3 operaciones de escritura y que tus reglas de seguridad usan 2 llamadas de acceso a documentos para validar cada escritura. En este caso, cada escritura utiliza 2 de sus 10 llamadas de acceso, y la solicitud de escritura en lotes utiliza 6 de sus 20 llamadas de acceso.

Si se excede alguno de esos límites, se obtiene un error de permiso denegado.

Algunas llamadas de acceso a documentos se pueden almacenar en caché, y estas llamadas no cuentan para los límites.

Profundidad máxima de las declaraciones match anidadas 10
Longitud máxima de la ruta de acceso, en segmentos de ruta, permitida en un conjunto de declaraciones match anidadas: 100
Cantidad máxima de variables de captura de rutas de acceso permitida en un conjunto de instrucciones match anidadas 20
Profundidad máxima de las llamadas a funciones 20
Cantidad máxima de argumentos de funciones 7
Cantidad máxima de vinculaciones a variables let por función 10
Cantidad máxima de llamadas recurrentes o cíclicas a una función 0 (no permitidas)
Cantidad máxima de expresiones evaluadas por solicitud 1,000
Tamaño máximo de un conjunto de reglas Los conjuntos de reglas deben cumplir con dos límites de tamaño:
  • 256 KB en el tamaño del texto origen del conjunto de reglas publicado desde la consola de Firebase o la CLI con firebase deploy.
  • 250 KB en el tamaño del conjunto de reglas compilado que se genera cuando Firebase procesa la fuente y la activa en el backend

Próximos pasos