Consulta datos de forma segura

En esta página, se amplían los conceptos mencionados en Estructura las reglas de seguridad y Condiciones de escritura de las reglas de seguridad para explicar la forma en que interactúan las consultas con las reglas de seguridad de Cloud Firestore. Examina con más detalle la manera en que las reglas de seguridad afectan a las consultas que puedes escribir y describe cómo garantizar que las consultas usen las mismas restricciones que tus reglas de seguridad. Esta página también explica cómo escribir reglas de seguridad para permitir o rechazar consultas según las propiedades de una consulta, como limit y orderBy.

Consultas y reglas de seguridad

Cuando escribas consultas para recuperar documentos, ten en cuenta que las reglas de seguridad no son filtros: las consultas son todo o nada. Para ahorrar tiempo y recursos, Cloud Firestore evalúa una consulta en comparación con su conjunto de resultados potenciales en lugar de con los valores de campo reales para todos tus documentos. Si una consulta llegara a mostrar documentos que el cliente no tiene permiso para leer, fallará toda la solicitud.

Tal como demuestran los ejemplos a continuación, debes escribir tus consultas de modo que se adapten a las restricciones de tus reglas de seguridad.

Cómo asegurar y consultar documentos basados en auth.uid

El siguiente ejemplo demuestra cómo escribir una consulta para recuperar documentos protegidos por una regla de seguridad. Considera una base de datos que contenga una colección de documentos story:

/stories/{storyid}

{
  title: "A Great Story",
  content: "Once upon a time...",
  author: "some_auth_id",
  published: false
}

Además de los campos title y content, cada documento almacena los campos author y published para usar para control de acceso. En estos ejemplos, se supone que la app usa Firebase Authentication para configurar el campo author como el UID del usuario que creó el documento. Firebase Authentication también llena la variable request.auth en las reglas de seguridad.

La siguiente regla de seguridad usa las variables request.auth y resource.data a fin de restringir el acceso de lectura y escritura para cada story a su autor:

service cloud.firestore {
  match /databases/{database}/documents {
    match /stories/{storyid} {
      // Only the authenticated user who authored the document can read or write
      allow read, write: if request.auth.uid == resource.data.author;
    }
  }
}

Supón que tu app incluye una página que muestra a los usuarios una lista de documentos story que ellos mismos crearon. Es de esperar que puedas usar la siguiente consulta para llenar esta página. Sin embargo, esta consulta fallará porque no incluye las mismas restricciones que tus reglas de seguridad:

No válido: Las restricciones de la consulta no coinciden con las restricciones de las reglas de seguridad

// This query will fail
db.collection("stories").get()

No se logra realizar la consulta incluso si el usuario actual es realmente el autor de cada documento story. La razón de este comportamiento es que, cuando Cloud Firestore aplica tus reglas de seguridad, evalúa la consulta en comparación con su conjunto de resultados posibles, no con las propiedades reales de los documentos de la base de datos. Si una consulta llegara a incluir documentos que violen tus reglas de seguridad, la consulta fallará.

Por el contrario, la siguiente consulta se ejecuta de forma correcta porque incluye la misma restricción en el campo author que las reglas de seguridad:

Válido: Las restricciones de la consulta coinciden con las restricciones de las reglas de seguridad

var user = firebase.auth().currentUser;

db.collection("stories").where("author", "==", user.uid).get()

Cómo asegurar y consultar documentos basados en un campo

Para demostrar aún más la interacción entre consultas y reglas, las siguientes reglas de seguridad amplían el acceso de lectura para la colección stories para que cualquier usuario pueda leer los documentos de story donde el campo published esté configurado en true.

service cloud.firestore {
  match /databases/{database}/documents {
    match /stories/{storyid} {
      // Anyone can read a published story; only story authors can read unpublished stories
      allow read: if resource.data.published == true || request.auth.uid == resource.data.author;
      // Only story authors can write
      allow write: if request.auth.uid == resource.data.author;
    }
  }
}

La consulta para páginas publicadas debe incluir las mismas restricciones que las reglas de seguridad:

db.collection("stories").where("published", "==", true).get()

La restricción de consulta .where("published", "==", true) garantiza que resource.data.published sea true para cualquier resultado. Por lo tanto, esta consulta cumple con las reglas de seguridad y tiene permitido leer los datos.

Cómo evaluar restricciones en consultas

Tus reglas de seguridad también pueden aceptar o rechazar consultas según sus restricciones. La variable request.query contiene las propiedades limit, offset y orderBy de una consulta. Por ejemplo, tus reglas de seguridad pueden rechazar cualquier consulta que no limite la cantidad máxima de documentos recuperados a un cierto rango:

allow list: if request.query.limit <= 10;

El siguiente conjunto de reglas demuestra cómo escribir reglas de seguridad que evalúen las restricciones impuestas a las consultas. Este ejemplo amplía el conjunto de reglas stories con los siguientes cambios:

  • El conjunto de reglas separa la regla read en reglas para get y list.
  • La regla get restringe la recuperación de documentos individuales a documentos públicos o documentos que haya creado el usuario.
  • La regla list aplica las mismas restricciones que get, pero para consultas. También verifica el límite de consulta y, luego, rechaza cualquier consulta sin límite o con un límite superior a 10.
  • El conjunto de reglas define una función authorOrPublished() para evitar la duplicación de código.
service cloud.firestore {

  match /databases/{database}/documents {

    match /stories/{storyid} {

      // Returns `true` if the requested story is 'published'
      // or the user authored the story
      function authorOrPublished() {
        return resource.data.published == true || request.auth.uid == resource.data.author;
      }

      // Deny any query not limited to 10 or fewer documents
      // Anyone can query published stories
      // Authors can query their unpublished stories
      allow list: if request.query.limit <= 10 &&
                     authorOrPublished();

      // Anyone can retrieve a published story
      // Only a story's author can retrieve an unpublished story
      allow get: if authorOrPublished();

      // Only a story's authors can write to a story
      allow write: if request.auth.uid == resource.data.author;
    }

  }
}

Próximos pasos

Enviar comentarios sobre…

¿Necesitas ayuda? Visita nuestra página de asistencia.