Condiciones de redacción para las reglas de seguridad de Cloud Firestore

Esta guía se basa en la guía de estructuración de reglas de seguridad para mostrar cómo agregar condiciones a sus reglas de seguridad de Cloud Firestore. Si no está familiarizado con los conceptos básicos de las reglas de seguridad de Cloud Firestore, consulte la guía de introducción .

El componente principal de las reglas de seguridad de Cloud Firestore es la condición. Una condición es una expresión booleana que determina si se debe permitir o denegar una operación particular. Utilice reglas de seguridad para escribir condiciones que verifiquen la autenticación del usuario, validen los datos entrantes o incluso accedan a otras partes de su base de datos.

Autenticación

Uno de los patrones de reglas de seguridad más comunes es controlar el acceso según el estado de autenticación del usuario. Por ejemplo, es posible que su aplicación desee permitir que solo los usuarios que hayan iniciado sesión escriban datos:

service cloud.firestore {
  match /databases/{database}/documents {
    // Allow the user to access documents in the "cities" collection
    // only if they are authenticated.
    match /cities/{city} {
      allow read, write: if request.auth != null;
    }
  }
}

Otro patrón común es asegurarse de que los usuarios solo puedan leer y escribir sus propios datos:

service cloud.firestore {
  match /databases/{database}/documents {
    // Make sure the uid of the requesting user matches name of the user
    // document. The wildcard expression {userId} makes the userId variable
    // available in rules.
    match /users/{userId} {
      allow read, update, delete: if request.auth != null && request.auth.uid == userId;
      allow create: if request.auth != null;
    }
  }
}

Si su aplicación utiliza Firebase Authentication o Google Cloud Identity Platform , la variable request.auth contiene la información de autenticación para el cliente que solicita datos. Para obtener más información sobre request.auth , consulte la documentación de referencia .

Validación de datos

Muchas aplicaciones almacenan información de control de acceso como campos de documentos en la base de datos. Las reglas de seguridad de Cloud Firestore pueden permitir o denegar el acceso dinámicamente según los datos del documento:

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

La variable resource se refiere al documento solicitado y resource.data es un mapa de todos los campos y valores almacenados en el documento. Para obtener más información sobre la variable resource , consulte la documentación de referencia .

Al escribir datos, es posible que desee comparar los datos entrantes con los datos existentes. En este caso, si su conjunto de reglas permite la escritura pendiente, la variable request.resource contiene el estado futuro del documento. Para operaciones update que solo modifican un subconjunto de los campos del documento, la variable request.resource contendrá el estado del documento pendiente después de la operación. Puede verificar los valores de los campos en request.resource para evitar actualizaciones de datos no deseadas o inconsistentes:

service cloud.firestore {
  match /databases/{database}/documents {
    // Make sure all cities have a positive population and
    // the name is not changed
    match /cities/{city} {
      allow update: if request.resource.data.population > 0
                    && request.resource.data.name == resource.data.name;
    }
  }
}

Acceder a otros documentos

Usando las funciones get() y exists() , sus reglas de seguridad pueden evaluar las solicitudes entrantes con respecto a otros documentos en la base de datos. Las funciones get() y exists() esperan rutas de documentos completamente especificadas. Cuando se utilizan variables para construir rutas para get() y exists() , es necesario escapar explícitamente de las variables utilizando la sintaxis $(variable) .

En el siguiente ejemplo, la variable database es capturada por la declaración de coincidencia match /databases/{database}/documents y se utiliza para formar la ruta:

service cloud.firestore {
  match /databases/{database}/documents {
    match /cities/{city} {
      // Make sure a 'users' document exists for the requesting user before
      // allowing any writes to the 'cities' collection
      allow create: if request.auth != null && exists(/databases/$(database)/documents/users/$(request.auth.uid))

      // Allow the user to delete cities if their user document has the
      // 'admin' field set to 'true'
      allow delete: if request.auth != null && get(/databases/$(database)/documents/users/$(request.auth.uid)).data.admin == true
    }
  }
}

Para las escrituras, puede utilizar la función getAfter() para acceder al estado de un documento después de que se complete una transacción o un lote de escrituras, pero antes de que se confirme la transacción o el lote. Al igual que get() , la función getAfter() toma una ruta de documento completamente especificada. Puede utilizar getAfter() para definir conjuntos de escrituras que deben realizarse juntas como una transacción o un lote.

Acceder a límites de llamadas

Existe un límite en las llamadas de acceso a documentos por evaluación de conjunto de reglas:

  • 10 para solicitudes de documento único y solicitudes de consulta.
  • 20 para lecturas, transacciones y escrituras por lotes de múltiples documentos. El límite anterior de 10 también se aplica a cada operación.

    Por ejemplo, imagine que crea una solicitud de escritura por lotes con 3 operaciones de escritura y que sus reglas de seguridad utilizan 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 por lotes utiliza 6 de sus 20 llamadas de acceso.

Exceder cualquiera de los límites da como resultado un error de permiso denegado. Algunas llamadas de acceso a documentos pueden almacenarse en caché y las llamadas en caché no cuentan para los límites.

Para obtener una explicación detallada de cómo estos límites afectan las transacciones y las escrituras por lotes, consulte la guía para proteger operaciones atómicas .

Acceder a llamadas y precios

El uso de estas funciones ejecuta una operación de lectura en su base de datos, lo que significa que se le facturará por leer los documentos incluso si sus reglas rechazan la solicitud. Consulta Precios de Cloud Firestore para obtener información de facturación más específica.

Funciones personalizadas

A medida que sus reglas de seguridad se vuelven más complejas, es posible que desee incluir conjuntos de condiciones en funciones que pueda reutilizar en todo su conjunto de reglas. Las reglas de seguridad admiten funciones personalizadas. La sintaxis de las funciones personalizadas es un poco parecida a JavaScript, pero las funciones de reglas de seguridad están escritas en un lenguaje específico de dominio que tiene algunas limitaciones importantes:

  • Las funciones pueden contener solo una única declaración return . No pueden contener ninguna lógica adicional. Por ejemplo, no pueden ejecutar bucles ni llamar a servicios externos.
  • Las funciones pueden acceder automáticamente a funciones y variables desde el ámbito en el que están definidas. Por ejemplo, una función definida dentro del alcance del service cloud.firestore tiene acceso a la variable resource y a funciones integradas como get() y exists() .
  • Las funciones pueden llamar a otras funciones pero no pueden repetirse. La profundidad total de la pila de llamadas está limitada a 10.
  • En la versión v2 de las reglas, las funciones pueden definir variables usando la palabra clave let . Las funciones pueden tener hasta 10 enlaces let, pero deben finalizar con una declaración de devolución.

Una función se define con la palabra clave function y toma cero o más argumentos. Por ejemplo, es posible que desees combinar los dos tipos de condiciones utilizadas en los ejemplos anteriores en una sola función:

service cloud.firestore {
  match /databases/{database}/documents {
    // 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 /cities/{city} {
      allow read, write: if signedInOrPublic();
    }

    match /users/{user} {
      allow read, write: if signedInOrPublic();
    }
  }
}

El uso de funciones en sus reglas de seguridad las hace más fáciles de mantener a medida que crece la complejidad de sus reglas.

Las reglas no son filtros

Una vez que proteja sus datos y comience a escribir consultas, tenga en cuenta que las reglas de seguridad no son filtros. No puede escribir una consulta para todos los documentos de una colección y esperar que Cloud Firestore devuelva solo los documentos a los que el cliente actual tiene permiso para acceder.

Por ejemplo, tomemos la siguiente regla de seguridad:

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

Denegado : esta regla rechaza la siguiente consulta porque el conjunto de resultados puede incluir documentos cuya visibility no es public :

Web
db.collection("cities").get()
    .then(function(querySnapshot) {
        querySnapshot.forEach(function(doc) {
            console.log(doc.id, " => ", doc.data());
    });
});

Permitido : esta regla permite la siguiente consulta porque la cláusula where("visibility", "==", "public") garantiza que el conjunto de resultados satisface la condición de la regla:

Web
db.collection("cities").where("visibility", "==", "public").get()
    .then(function(querySnapshot) {
        querySnapshot.forEach(function(doc) {
            console.log(doc.id, " => ", doc.data());
        });
    });

Las reglas de seguridad de Cloud Firestore evalúan cada consulta con respecto a su posible resultado y fallan la solicitud si pudiera devolver un documento que el cliente no tiene permiso para leer. Las consultas deben seguir las restricciones establecidas por sus reglas de seguridad. Para obtener más información sobre consultas y reglas de seguridad, consulte Consulta de datos de forma segura .

Próximos pasos