Implementa y administra las reglas de seguridad de Firebase

Firebase te proporciona varias herramientas para administrar tus reglas, todas útiles en casos particulares y cada una con la misma API de administración de reglas de seguridad de Firebase de backend.

No importa qué herramienta se utilice para invocarla, la API de administración realiza las siguientes acciones:

  • Transfiere una fuente de reglas: un conjunto de reglas, generalmente un archivo de código que contiene sentencias de las reglas de seguridad de Firebase.
  • Almacena la fuente transferida como un conjunto de reglas inmutable.
  • Realiza un seguimiento de la implementación de cada conjunto de reglas de una versión. Los servicios habilitados para reglas de seguridad de Firebase buscan la versión de un proyecto a fin de evaluar cada solicitud de un recurso protegido.
  • Proporciona la capacidad para ejecutar pruebas sintácticas y semánticas de un conjunto de reglas.

Usa Firebase CLI

Con Firebase CLI, puedes subir fuentes locales y, además, implementar versiones. Firebase Local Emulator Suite de CLI te permite realizar pruebas locales completas de las fuentes.

El uso de CLI te permite mantener las reglas bajo control de versión con el código de la aplicación y, además, aplicar reglas como parte del proceso de implementación existente.

Genera un archivo de configuración

Cuando configuras tu proyecto de Firebase con Firebase CLI, creas un archivo de configuración .rules en el directorio del proyecto. Usa el siguiente comando para comenzar la configuración del proyecto de Firebase:

Cloud Firestore

// Set up Firestore in your project directory, creates a .rules file
firebase init firestore

Realtime Database

// Set up Realtime Database in your project directory, creates a .rules file
firebase init database

Cloud Storage

// Set up Storage in your project directory, creates a .rules file
firebase init storage

Edita y actualiza tus reglas

Edita la fuente de las reglas directamente en el archivo de configuración .rules. Asegúrate de que las modificaciones que realices en Firebase CLI se reflejen en Firebase console, o de realizar actualizaciones de forma coherente con Firebase console o Firebase CLI. De lo contrario, es posible que reemplaces las actualizaciones realizadas en Firebase console.

Prueba tus actualizaciones

Local Emulator Suite proporciona emuladores para todos los productos habilitados para las reglas de seguridad. El motor de reglas de seguridad por cada emulador realiza una evaluación sintáctica y semántica de las reglas, lo que supera la prueba sintáctica que ofrece la API de administración de reglas de seguridad.

Si trabajas con CLI, Suite es una excelente herramienta para las pruebas de reglas de seguridad de Firebase. Usa Local Emulator Suite para probar tus actualizaciones de forma local y confirmar que las reglas de tu app exhiben el comportamiento que deseas.

Implementa tus actualizaciones

Una vez que hayas actualizado y probado las reglas, implementa las fuentes en producción. Usa los siguientes comandos para implementar de manera selectiva solo tus reglas o hacerlo como parte del proceso de implementación normal.

Cloud Firestore

// Deploy your .rules file
firebase deploy --only firestore:rules

Realtime Database

// Deploy your .rules file
firebase deploy --only database

Cloud Storage

// Deploy your .rules file
firebase deploy --only storage

Usa Firebase console

También puedes editar fuentes de reglas y, luego, implementarlas como versiones desde Firebase console. Las pruebas sintácticas se realizan mientras haces modificaciones en la IU de Firebase console, y las pruebas semánticas están disponibles mediante la Zona de pruebas de reglas.

Edita y actualiza tus reglas

  1. Abre Firebase console y selecciona tu proyecto.
  2. Luego selecciona Realtime Database, Cloud Firestore o Storage en la navegación del producto y, luego, haz clic en Reglas para navegar al editor de reglas.
  3. Edita tus reglas directamente en el editor.

Prueba tus actualizaciones

Además de probar la sintaxis en la IU del editor, puedes probar el comportamiento de las reglas semánticas mediante la base de datos de tu proyecto y los recursos de almacenamiento, directamente en Firebase console, con el comando Zona de pruebas de reglas. Abre la pantalla Zona de pruebas de reglas en el editor de reglas, modifica la configuración y haz clic en Ejecutar. Busca el mensaje de confirmación en la parte superior del editor.

Implementa tus actualizaciones

Una vez que estés satisfecho con las actualizaciones, haz clic en Publicar.

Usa el SDK de Admin

Puedes usar el SDK de Admin para los conjuntos de reglas de Node.js. Con este acceso programático, puedes hacer lo siguiente:

  • Implementa herramientas personalizadas, secuencias de comandos, paneles y canalizaciones de CI/CD para administrar las reglas.
  • Administra reglas con más facilidad en varios proyectos de Firebase.

Cuando se actualizan las reglas de manera programática, es muy importante evitar los cambios no deseados en el control de acceso de la app. Escribe el código del SDK de Admin con la seguridad en mente, especialmente cuando actualices o implementes reglas.

Otro punto importante que se debe tener en cuenta es que las reglas de seguridad de Firebase tardan varios minutos en propagarse por completo. Cuando uses el SDK de Admin para implementar reglas, asegúrate de evitar las condiciones de carrera en las que la app dependa de inmediato de reglas cuya implementación aún no se haya completado. Si tu caso práctico requiere actualizaciones frecuentes para las reglas de control de acceso, considera las soluciones que usan Cloud Firestore, que está diseñado para reducir las condiciones de carrera a pesar de las actualizaciones frecuentes.

También ten en cuenta estos límites:

  • El tamaño de las reglas debe ser menor que 256 KiB de texto codificado en UTF-8 cuando se serializan.
  • Un proyecto puede tener un máximo de 2,500 conjuntos de reglas implementados. Una vez que se alcanza este límite, debes borrar algunos conjuntos de reglas antiguos antes de crear otros nuevos.

Crea e implementa conjuntos de reglas de Cloud Storage o Cloud Firestore

Un flujo de trabajo típico para administrar reglas de seguridad con el SDK de Admin podría incluir los tres pasos discretos siguientes:

  1. Crear una fuente de archivo de reglas (opcional)
  2. Crear un conjunto de reglas
  3. Lanzar o implementar el nuevo conjunto de reglas

El SDK proporciona un método para combinar estos pasos en una sola llamada a la API para las reglas de seguridad de Cloud Storage y Cloud Firestore. Por ejemplo:

    const source = `service cloud.firestore {
      match /databases/{database}/documents {
        match /carts/{cartID} {
          allow create: if request.auth != null && request.auth.uid == request.resource.data.ownerUID;
          allow read, update, delete: if request.auth != null && request.auth.uid == resource.data.ownerUID;
        }
      }
    }`;
    // Alternatively, load rules from a file
    // const fs = require('fs');
    // const source = fs.readFileSync('path/to/firestore.rules', 'utf8');

    await admin.securityRules().releaseFirestoreRulesetFromSource(source);

Este mismo patrón funciona para las reglas de Cloud Storage con releaseFirestoreRulesetFromSource().

Como alternativa, puedes crear el archivo de reglas como un objeto en la memoria, crear el conjunto de reglas y, luego, implementar el conjunto de reglas por separado para controlar mejor estos eventos. Por ejemplo:

    const rf = admin.securityRules().createRulesFileFromSource('firestore.rules', source);
    const rs = await admin.securityRules().createRuleset(rf);
    await admin.securityRules().releaseFirestoreRuleset(rs);

Actualiza conjuntos de reglas de Realtime Database

Para actualizar los conjuntos de reglas de Realtime Database con el SDK de Admin, usa los métodos getRules() y setRules() de admin.database. Puedes recuperar conjuntos de reglas en formato JSON o una string con comentarios incluidos.

Usa el siguiente código para actualizar un conjunto de reglas:

    const source = `{
      "rules": {
        "scores": {
          ".indexOn": "score",
          "$uid": {
            ".read": "$uid == auth.uid",
            ".write": "$uid == auth.uid"
          }
        }
      }
    }`;
    await admin.database().setRules(source);

Administra conjuntos de reglas

Para ayudar a administrar conjuntos de reglas grandes, el SDK de Admin te permite enumerar todas las reglas existentes con admin.securityRules().listRulesetMetadata. Por ejemplo:

    const allRulesets = [];
    let pageToken = null;
    while (true) {
      const result = await admin.securityRules().listRulesetMetadata(pageToken: pageToken);
      allRulesets.push(...result.rulesets);
      pageToken = result.nextPageToken;
      if (!pageToken) {
        break;
      }
    }

Para implementaciones muy grandes que, con el tiempo, alcanzan el límite de 2,500 conjuntos de reglas, puedes crear una lógica a fin de borrar las reglas más antiguas en un ciclo de tiempo fijo. Usa el siguiente ejemplo para borrar todos los conjuntos de reglas implementados durante más de 30 días:

    const thirtyDays = new Date(Date.now() - THIRTY_DAYS_IN_MILLIS);
    const promises = [];
    allRulesets.forEach((rs) => {
      if (new Date(rs.createTime) < thirtyDays) {
        promises.push(admin.securityRules().deleteRuleset(rs.name));
      }
    });
    await Promise.all(promises);
    console.log(`Deleted ${promises.length} rulesets.`);

Usa la API de REST

Las herramientas descritas anteriormente son adecuadas para flujos de trabajo, pero puedes administrar y también implementar las reglas de seguridad de Firebase con la API de administración. La API de administración te brinda la mayor flexibilidad.

Ten en cuenta que las versiones de las reglas de seguridad de Firebase tardan varios minutos en propagarse por completo. Cuando uses la API de REST de administración para realizar implementaciones, asegúrate de evitar condiciones de carrera en las que la app dependa de inmediato de reglas cuya implementación aún no se haya completado.

También ten en cuenta estos límites:

  • El tamaño de las reglas debe ser menor que 256 KiB de texto codificado en UTF-8 cuando se serializan.
  • Un proyecto puede tener un máximo de 2,500 conjuntos de reglas implementados. Una vez que se alcanza este límite, debes borrar algunos conjuntos de reglas antiguos antes de crear otros nuevos.

Crea y, luego, implementa conjuntos de reglas de Cloud Storage o Cloud Firestore con REST

En los ejemplos de esta sección se usan reglas de almacenamiento, aunque también se aplican a las reglas de Cloud Firestore.

En los ejemplos también se usa cURL para realizar llamadas a la API. Se omiten los pasos para configurar y pasar tokens de autenticación. Puedes experimentar con esta API a través del Explorador de API integrado en la documentación de referencia.

Los pasos típicos para crear y, luego, implementar un conjunto de reglas mediante la API de administración son los siguientes:

  1. Crear una fuente de archivo de reglas
  2. Crear un conjunto de reglas
  3. Lanzar (implementar) el nuevo conjunto de reglas

Supongamos que estás trabajando en tu proyecto de Firebase secure_commerce y deseas implementar reglas de Cloud Storage bloqueadas. Puedes implementar estas reglas en un archivo storage.rules.

service firebase.storage {
  match /b/{bucket}/o {
    match /{allPaths=**} {
      allow read, write: if false;
    }
  }
}

Ahora, genera una huella digital codificada en Base64 para este archivo. Puedes usar la fuente en este archivo para propagar la carga útil necesaria a fin de crear un conjunto de reglas con la llamada de REST projects.rulesets.create. Aquí, usamos el comando cat para insertar el contenido de storage.rules en la carga útil de REST.

curl -X POST -d '{
  "source": {
    {
      "files": [
        {
          "content": "' $(cat storage.rules) '",
          "name": "storage.rules",
          "fingerprint": <sha fingerprint>
        }
      ]
    }
  }
}' 'https://firebaserules.googleapis.com/v1/projects/secure_commerce/rulesets'

La API muestra una respuesta de validación y un nombre de conjunto de reglas, por ejemplo, projects/secure_commerce/rulesets/uuid123. Si el conjunto de reglas es válido, el último paso es implementar el nuevo conjunto de reglas en una versión con nombre.

curl -X POST -d '{
  "name": "projects/secure_commerce/releases/prod/v23   "  ,
  "rulesetName": "projects/secure_commerce/rulesets/uuid123",
}' 'https://firebaserules.googleapis.com/v1/projects/secure_commerce/releases'

Actualiza conjuntos de reglas de Realtime Database con REST

Realtime Database brinda su propia interfaz de REST para administrar reglas. Consulta Administra las reglas de Firebase Realtime Database mediante REST

Administra conjuntos de reglas con REST

A fin de ayudar a administrar grandes implementaciones de reglas, además de un método REST para crear conjuntos de reglas y versiones, la API de administración proporciona métodos con el fin de realizar las siguientes acciones:

  • enumerar, obtener y borrar conjuntos de reglas
  • enumerar, obtener y borrar versiones de reglas

Para implementaciones muy grandes que, con el tiempo, alcanzan el límite de 2,500 conjuntos de reglas, puedes crear una lógica a fin de borrar las reglas más antiguas en un ciclo de tiempo fijo. Por ejemplo, para borrar todos los conjuntos de reglas implementados durante más de 30 días, puedes llamar al método projects.rulesets.list, analizar la lista JSON de los objetos Ruleset en sus claves createTime y, luego, llamar a project.rulesets.delete en los conjuntos de reglas correspondientes por ruleset_id.

Prueba tus actualizaciones con REST

Finalmente, la API de administración te permite ejecutar pruebas sintácticas y semánticas en los recursos de Cloud Firestore y Cloud Storage de tus proyectos de producción.

Las pruebas con este componente de la API consisten en realizar lo siguiente:

  1. Definir un objeto JSON TestSuite para representar un conjunto de objetos TestCase
  2. Enviar el TestSuite
  3. Analizar los objetos TestResult que se muestran

Definamos un objeto TestSuite con un único TestCase en un archivo testcase.json. En este ejemplo, pasamos la fuente del lenguaje de las reglas intercalada con la carga útil de REST, junto con el conjunto de pruebas que se ejecutarán en esas reglas. Especificamos una expectativa de evaluación de reglas y la solicitud de cliente en la que se probará el conjunto de reglas. También puedes especificar qué tan completo quieres que sea el informe de pruebas con el valor “FULL” para indicar que se deben incluir los resultados de todas las expresiones de lenguaje de las reglas, incluidas aquellas que no coincidan con la solicitud.

 {
  "source":
  {
    "files":
    [
      {
        "name": "firestore.rules",
        "content": "service cloud.firestore {
          match /databases/{database}/documents {
            match /users/{userId}{
              allow read: if (request.auth.uid == userId);
            }
            function doc(subpath) {
              return get(/databases/$(database)/documents/$(subpath)).data;
            }
            function isAccountOwner(accountId) {
              return request.auth.uid == accountId
                  || doc(/users/$(request.auth.uid)).accountId == accountId;
            }
            match /licenses/{accountId} {
              allow read: if isAccountOwner(accountId);
            }
          }
        }"
      }
    ]
  },
  "testSuite":
  {
    "testCases":
    [
      {
        "expectation": "ALLOW",
        "request": {
           "auth": {"uid": "123"},
           "path": "/databases/(default)/documents/licenses/abcd",
           "method": "get"},
        "functionMocks": [
            {
            "function": "get",
            "args": [{"exact_value": "/databases/(default)/documents/users/123"}],
            "result": {"value": {"data": {"accountId": "abcd"}}}
            }
          ]
      }
    ]
  }
}

Luego, podemos enviar este TestSuite para que se evalúe con el método projects.test.

curl -X POST -d '{
    ' $(cat testcase.json) '
}' 'https://firebaserules.googleapis.com/v1/projects/secure_commerce/rulesets/uuid123:test'

El TestReport que se muestra (que contiene el estado SUCCESS/FAILURE de la prueba, las listas de mensajes de depuración, las listas de expresiones de reglas visitadas y sus informes de evaluación) confirmaría con el estado SUCCESS que el acceso está permitido de forma correcta.

Administra permisos para reglas de seguridad de Cloud Storage entre servicios

Si creas reglas de seguridad de Cloud Storage que usan contenido de documentos de Cloud Firestore para evaluar las condiciones de seguridad, se te pedirá que habilites permisos en Firebase console o Firebase CLI a fin de conectar los dos productos.

Si decides inhabilitar esa seguridad entre servicios, haz lo siguiente:

  1. Antes de inhabilitar la función, edita las reglas y quita todas las declaraciones que usan funciones de reglas para acceder a Cloud Firestore. De lo contrario, después de que se inhabilite la función, las evaluaciones de reglas provocarán que las solicitudes de Storage fallen.

  2. Usa la página de IAM en la consola de Google Cloud a fin de borrar el rol “Agente de servicio de Firestore para las reglas de Firebase” mediante la guía de Cloud para revocar roles.

Se te solicitará que vuelvas a habilitar la función la próxima vez que guardes reglas entre servicios desde Firebase CLI o Firebase console.