Lenguaje de reglas de seguridad

Las reglas de seguridad de Firebase aprovechan lenguajes flexibles, potentes y personalizados que admiten una amplia gama de complejidad y granularidad. Puede hacer que sus Reglas sean tan específicas o tan generales como tenga sentido para su aplicación. Las reglas de Realtime Database utilizan una sintaxis similar a JavaScript en una estructura JSON. Las reglas de Cloud Firestore y Cloud Storage usan un lenguaje basado en el lenguaje de expresión común (CEL) , que se basa en CEL con declaraciones match y allow que admiten acceso concedido condicionalmente.

Sin embargo, debido a que se trata de lenguajes personalizados, existe una curva de aprendizaje. Utilice esta guía para comprender mejor el lenguaje de las reglas a medida que profundiza en reglas más complejas.

Seleccione un producto para obtener más información sobre sus reglas.

Estructura basica

Tienda de fuego en la nube

Las reglas de seguridad de Firebase en Cloud Firestore y Cloud Storage utilizan la siguiente estructura y sintaxis:

service <<name>> {
  // Match the resource path.
  match <<path>> {
    // Allow the request if the following conditions are true.
    allow <<methods>> : if <<condition>>
  }
}

Es importante comprender los siguientes conceptos clave al crear las reglas:

  • Solicitud: el método o métodos invocados en la declaración allow . Estos son métodos que estás permitiendo ejecutar. Los métodos estándar son: get , list , create , update y delete . Los métodos convenientes read y write permiten un amplio acceso de lectura y escritura en la base de datos o ruta de almacenamiento especificada.
  • Ruta: la base de datos o la ubicación de almacenamiento, representada como una ruta URI.
  • Regla: la declaración allow , que incluye una condición que permite una solicitud si se evalúa como verdadera.

Cada uno de estos conceptos se describe con más detalle a continuación.

Almacenamiento en la nube

Las reglas de seguridad de Firebase en Cloud Firestore y Cloud Storage utilizan la siguiente estructura y sintaxis:

service <<name>> {
  // Match the resource path.
  match <<path>> {
    // Allow the request if the following conditions are true.
    allow <<methods>> : if <<condition>>
  }
}

Es importante comprender los siguientes conceptos clave al crear las reglas:

  • Solicitud: el método o métodos invocados en la declaración allow . Estos son métodos que estás permitiendo ejecutar. Los métodos estándar son: get , list , create , update y delete . Los métodos convenientes read y write permiten un amplio acceso de lectura y escritura en la base de datos o ruta de almacenamiento especificada.
  • Ruta: la base de datos o la ubicación de almacenamiento, representada como una ruta URI.
  • Regla: la declaración allow , que incluye una condición que permite una solicitud si se evalúa como verdadera.

Cada uno de estos conceptos se describe con más detalle a continuación.

Base de datos en tiempo real

En Realtime Database, las reglas de seguridad de Firebase consisten en expresiones similares a JavaScript contenidas en un documento JSON.

Utilizan la siguiente sintaxis:

{
  "rules": {
    "<<path>>": {
    // Allow the request if the condition for each method is true.
      ".read": <<condition>>,
      ".write": <<condition>>,
      ".validate": <<condition>>
    }
  }
}

Hay tres elementos básicos en la regla:

  • Ruta: la ubicación de la base de datos. Esto refleja la estructura JSON de su base de datos.
  • Solicitud: estos son los métodos que utiliza la regla para otorgar acceso. Las reglas read y write otorgan un amplio acceso de lectura y escritura, mientras que las reglas validate actúan como una verificación secundaria para otorgar acceso según los datos entrantes o existentes.
  • Condición: la condición que permite una solicitud si se evalúa como verdadera.

Construcciones de reglas

Tienda de fuego en la nube

Los elementos básicos de una regla en Cloud Firestore y Cloud Storage son los siguientes:

  • La declaración service : declara el producto de Firebase al que se aplican las reglas.
  • El bloque match : define una ruta en la base de datos o depósito de almacenamiento al que se aplican las reglas.
  • La declaración allow : proporciona condiciones para otorgar acceso, diferenciadas por métodos. Los métodos admitidos incluyen: get , list , create , update , delete y los métodos convenientes read y write .
  • Declaraciones function opcionales: brindan la capacidad de combinar y ajustar condiciones para su uso en múltiples reglas.

El service contiene uno o más bloques match con declaraciones allow que proporcionan condiciones que otorgan acceso a las solicitudes. Las variables request y resource están disponibles para su uso en condiciones de reglas. El lenguaje de reglas de seguridad de Firebase también admite declaraciones function .

Versión de sintaxis

La declaración syntax indica la versión del lenguaje de reglas de Firebase utilizada para escribir la fuente. La última versión del idioma es v2 .

rules_version = '2';
service cloud.firestore {
...
}

Si no se proporciona ninguna declaración rules_version , sus reglas se evaluarán utilizando el motor v1 .

Servicio

La declaración de service define a qué producto o servicio de Firebase se aplican sus reglas. Solo puede incluir una declaración service por archivo fuente.

Tienda de fuego en la nube

service cloud.firestore {
 // Your 'match' blocks with their corresponding 'allow' statements and
 // optional 'function' declarations are contained here
}

Almacenamiento en la nube

service firebase.storage {
  // Your 'match' blocks with their corresponding 'allow' statements and
  // optional 'function' declarations are contained here
}

Si estás definiendo reglas para Cloud Firestore y Cloud Storage usando Firebase CLI, tendrás que mantenerlas en archivos separados.

Fósforo

Un bloque match declara un patrón path que coincide con la ruta de la operación solicitada (la request.path entrante). El cuerpo de la match debe tener uno o más bloques match anidados, declaraciones allow o declaraciones function . La ruta en los bloques match anidados es relativa a la ruta en el bloque match principal.

El patrón path es un nombre similar a un directorio que puede incluir variables o comodines. El patrón path permite coincidencias de segmentos de ruta única y segmentos de rutas múltiples. Cualquier variable vinculada a una path es visible dentro del alcance match o cualquier alcance anidado donde se declare la path .

Las coincidencias con un patrón path pueden ser parciales o completas:

  • Coincidencias parciales: el patrón path es una coincidencia de prefijo de request.path .
  • Coincidencias completas: el patrón path coincide con todo el request.path .

Cuando se realiza una coincidencia completa , se evalúan las reglas dentro del bloque. Cuando se realiza una coincidencia parcial , las reglas match anidada se prueban para ver si alguna path anidada completará la coincidencia.

Las reglas en cada match completa se evalúan para determinar si se permite la solicitud. Si alguna regla coincidente otorga acceso, se permite la solicitud. Si ninguna regla coincidente concede acceso, se deniega la solicitud.

// Given request.path == /example/hello/nested/path the following
// declarations indicate whether they are a partial or complete match and
// the value of any variables visible within the scope.
service firebase.storage {
  // Partial match.
  match /example/{singleSegment} {   // `singleSegment` == 'hello'
    allow write;                     // Write rule not evaluated.
    // Complete match.
    match /nested/path {             // `singleSegment` visible in scope.
      allow read;                    // Read rule is evaluated.
    }
  }
  // Complete match.
  match /example/{multiSegment=**} { // `multiSegment` == /hello/nested/path
    allow read;                      // Read rule is evaluated.
  }
}

Como muestra el ejemplo anterior, las declaraciones path admiten las siguientes variables:

  • Comodín de segmento único: una variable comodín se declara en una ruta envolviendo una variable entre llaves: {variable} . Se puede acceder a esta variable dentro de la declaración match como una string .
  • Comodín recursivo: el comodín recursivo o de múltiples segmentos coincide con múltiples segmentos de ruta en una ruta o debajo de ella. Este comodín coincide con todas las rutas debajo de la ubicación en la que lo configuró. Puede declararlo agregando la cadena =** al final de su variable de segmento: {variable=**} . Se puede acceder a esta variable dentro de la declaración match como un objeto path .

Permitir

El bloque match contiene una o más declaraciones allow . Estas son tus reglas reales. Puede aplicar reglas allow a uno o más métodos. Las condiciones de una declaración allow deben evaluarse como verdaderas para que Cloud Firestore o Cloud Storage concedan cualquier solicitud entrante. También puede escribir declaraciones allow sin condiciones, por ejemplo, allow read . Sin embargo, si la declaración de allow no incluye una condición, siempre permite la solicitud de ese método.

Si se cumple alguna de las reglas allow para el método, se permite la solicitud. Además, si una regla más amplia otorga acceso, las reglas otorgan acceso e ignoran cualquier regla más granular que pueda limitar el acceso.

Considere el siguiente ejemplo, donde cualquier usuario puede leer o eliminar cualquiera de sus propios archivos. Una regla más detallada solo permite escrituras si el usuario que solicita la escritura es propietario del archivo y el archivo es PNG. Un usuario puede eliminar cualquier archivo en la subruta, incluso si no son PNG, porque la regla anterior lo permite.

service firebase.storage {
  // Allow the requestor to read or delete any resource on a path under the
  // user directory.
  match /users/{userId}/{anyUserFile=**} {
    allow read, delete: if request.auth != null && request.auth.uid == userId;
  }

  // Allow the requestor to create or update their own images.
  // When 'request.method' == 'delete' this rule and the one matching
  // any path under the user directory would both match and the `delete`
  // would be permitted.

  match /users/{userId}/images/{imageId} {
    // Whether to permit the request depends on the logical OR of all
    // matched rules. This means that even if this rule did not explicitly
    // allow the 'delete' the earlier rule would have.
    allow write: if request.auth != null && request.auth.uid == userId && imageId.matches('*.png');
  }
}

Método

Cada declaración allow incluye un método que otorga acceso a solicitudes entrantes del mismo método.

Método Tipo de solicitud
Métodos de conveniencia
read Cualquier tipo de solicitud de lectura
write Cualquier tipo de solicitud de escritura
Métodos estándar
get Leer solicitudes de documentos o archivos individuales
list Leer solicitudes de consultas y cobros
create Escribir nuevos documentos o archivos
update Escribir en documentos de bases de datos existentes o actualizar metadatos de archivos
delete Borrar datos

No puede superponer métodos de lectura en el mismo bloque match ni métodos de escritura en conflicto en la misma declaración de path .

Por ejemplo, las siguientes reglas fallarían:

service bad.example {
  match /rules/with/overlapping/methods {
    // This rule allows reads to all authenticated users
    allow read: if request.auth != null;

    match another/subpath {
      // This secondary, more specific read rule causes an error
      allow get: if request.auth != null && request.auth.uid == "me";
      // Overlapping write methods in the same path cause an error as well
      allow write: if request.auth != null;
      allow create: if request.auth != null && request.auth.uid == "me";
    }
  }
}

Función

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 20.
  • 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();
    }
  }
}

A continuación se muestra un ejemplo que muestra argumentos de función y asignaciones let. Las declaraciones de asignación deben estar separadas por punto y coma.

function isAuthorOrAdmin(userId, article) {
  let isAuthor = article.author == userId;
  let isAdmin = exists(/databases/$(database)/documents/admins/$(userId));
  return isAuthor || isAdmin;
}

Observe cómo la asignación isAdmin exige una búsqueda de la colección de administradores. Para una evaluación diferida sin requerir búsquedas innecesarias, aproveche la naturaleza de cortocircuito de && (AND) y || (O) comparaciones para llamar a una segunda función solo si se muestra que isAuthor es verdadero (para comparaciones && ) o falso (para comparaciones || ).

function isAdmin(userId) {
  return exists(/databases/$(database)/documents/admins/$(userId));
}
function isAuthorOrAdmin(userId, article) {
  let isAuthor = article.author == userId;
  // `||` is short-circuiting; isAdmin called only if isAuthor == false.
  return isAuthor || isAdmin(userId);
}

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.

Almacenamiento en la nube

Los elementos básicos de una regla en Cloud Firestore y Cloud Storage son los siguientes:

  • La declaración service : declara el producto de Firebase al que se aplican las reglas.
  • El bloque match : define una ruta en la base de datos o depósito de almacenamiento al que se aplican las reglas.
  • La declaración allow : proporciona condiciones para otorgar acceso, diferenciadas por métodos. Los métodos admitidos incluyen: get , list , create , update , delete y los métodos convenientes read y write .
  • Declaraciones function opcionales: brindan la capacidad de combinar y ajustar condiciones para su uso en múltiples reglas.

El service contiene uno o más bloques match con declaraciones allow que proporcionan condiciones que otorgan acceso a las solicitudes. Las variables request y resource están disponibles para su uso en condiciones de reglas. El lenguaje de reglas de seguridad de Firebase también admite declaraciones function .

Versión de sintaxis

La declaración syntax indica la versión del lenguaje de reglas de Firebase utilizada para escribir la fuente. La última versión del idioma es v2 .

rules_version = '2';
service cloud.firestore {
...
}

Si no se proporciona ninguna declaración rules_version , sus reglas se evaluarán utilizando el motor v1 .

Servicio

La declaración de service define a qué producto o servicio de Firebase se aplican sus reglas. Solo puede incluir una declaración service por archivo fuente.

Tienda de fuego en la nube

service cloud.firestore {
 // Your 'match' blocks with their corresponding 'allow' statements and
 // optional 'function' declarations are contained here
}

Almacenamiento en la nube

service firebase.storage {
  // Your 'match' blocks with their corresponding 'allow' statements and
  // optional 'function' declarations are contained here
}

Si estás definiendo reglas para Cloud Firestore y Cloud Storage usando Firebase CLI, tendrás que mantenerlas en archivos separados.

Fósforo

Un bloque match declara un patrón path que coincide con la ruta de la operación solicitada (la request.path entrante). El cuerpo de la match debe tener uno o más bloques match anidados, declaraciones allow o declaraciones function . La ruta en los bloques match anidados es relativa a la ruta en el bloque match principal.

El patrón path es un nombre similar a un directorio que puede incluir variables o comodines. El patrón path permite coincidencias de segmentos de ruta única y segmentos de rutas múltiples. Cualquier variable vinculada a una path es visible dentro del alcance match o cualquier alcance anidado donde se declare la path .

Las coincidencias con un patrón path pueden ser parciales o completas:

  • Coincidencias parciales: el patrón path es una coincidencia de prefijo de request.path .
  • Coincidencias completas: el patrón path coincide con todo el request.path .

Cuando se realiza una coincidencia completa , se evalúan las reglas dentro del bloque. Cuando se realiza una coincidencia parcial , las reglas match anidada se prueban para ver si alguna path anidada completará la coincidencia.

Las reglas en cada match completa se evalúan para determinar si se permite la solicitud. Si alguna regla coincidente otorga acceso, se permite la solicitud. Si ninguna regla coincidente concede acceso, se deniega la solicitud.

// Given request.path == /example/hello/nested/path the following
// declarations indicate whether they are a partial or complete match and
// the value of any variables visible within the scope.
service firebase.storage {
  // Partial match.
  match /example/{singleSegment} {   // `singleSegment` == 'hello'
    allow write;                     // Write rule not evaluated.
    // Complete match.
    match /nested/path {             // `singleSegment` visible in scope.
      allow read;                    // Read rule is evaluated.
    }
  }
  // Complete match.
  match /example/{multiSegment=**} { // `multiSegment` == /hello/nested/path
    allow read;                      // Read rule is evaluated.
  }
}

Como muestra el ejemplo anterior, las declaraciones path admiten las siguientes variables:

  • Comodín de segmento único: una variable comodín se declara en una ruta envolviendo una variable entre llaves: {variable} . Se puede acceder a esta variable dentro de la declaración match como una string .
  • Comodín recursivo: el comodín recursivo o de múltiples segmentos coincide con múltiples segmentos de ruta en una ruta o debajo de ella. Este comodín coincide con todas las rutas debajo de la ubicación en la que lo configuró. Puede declararlo agregando la cadena =** al final de su variable de segmento: {variable=**} . Se puede acceder a esta variable dentro de la declaración match como un objeto path .

Permitir

El bloque match contiene una o más declaraciones allow . Estas son tus reglas reales. Puede aplicar reglas allow a uno o más métodos. Las condiciones de una declaración allow deben evaluarse como verdaderas para que Cloud Firestore o Cloud Storage concedan cualquier solicitud entrante. También puede escribir declaraciones allow sin condiciones, por ejemplo, allow read . Sin embargo, si la declaración de allow no incluye una condición, siempre permite la solicitud de ese método.

Si se cumple alguna de las reglas allow para el método, se permite la solicitud. Además, si una regla más amplia otorga acceso, las reglas otorgan acceso e ignoran cualquier regla más granular que pueda limitar el acceso.

Considere el siguiente ejemplo, donde cualquier usuario puede leer o eliminar cualquiera de sus propios archivos. Una regla más detallada solo permite escrituras si el usuario que solicita la escritura es propietario del archivo y el archivo es PNG. Un usuario puede eliminar cualquier archivo en la subruta, incluso si no son PNG, porque la regla anterior lo permite.

service firebase.storage {
  // Allow the requestor to read or delete any resource on a path under the
  // user directory.
  match /users/{userId}/{anyUserFile=**} {
    allow read, delete: if request.auth != null && request.auth.uid == userId;
  }

  // Allow the requestor to create or update their own images.
  // When 'request.method' == 'delete' this rule and the one matching
  // any path under the user directory would both match and the `delete`
  // would be permitted.

  match /users/{userId}/images/{imageId} {
    // Whether to permit the request depends on the logical OR of all
    // matched rules. This means that even if this rule did not explicitly
    // allow the 'delete' the earlier rule would have.
    allow write: if request.auth != null && request.auth.uid == userId && imageId.matches('*.png');
  }
}

Método

Cada declaración allow incluye un método que otorga acceso a solicitudes entrantes del mismo método.

Método Tipo de solicitud
Métodos de conveniencia
read Cualquier tipo de solicitud de lectura
write Cualquier tipo de solicitud de escritura
Métodos estándar
get Leer solicitudes de documentos o archivos individuales
list Leer solicitudes de consultas y cobros
create Escribir nuevos documentos o archivos
update Escribir en documentos de bases de datos existentes o actualizar metadatos de archivos
delete Borrar datos

No puede superponer métodos de lectura en el mismo bloque match ni métodos de escritura en conflicto en la misma declaración de path .

Por ejemplo, las siguientes reglas fallarían:

service bad.example {
  match /rules/with/overlapping/methods {
    // This rule allows reads to all authenticated users
    allow read: if request.auth != null;

    match another/subpath {
      // This secondary, more specific read rule causes an error
      allow get: if request.auth != null && request.auth.uid == "me";
      // Overlapping write methods in the same path cause an error as well
      allow write: if request.auth != null;
      allow create: if request.auth != null && request.auth.uid == "me";
    }
  }
}

Función

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 20.
  • 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();
    }
  }
}

A continuación se muestra un ejemplo que muestra argumentos de función y asignaciones let. Las declaraciones de asignación deben estar separadas por punto y coma.

function isAuthorOrAdmin(userId, article) {
  let isAuthor = article.author == userId;
  let isAdmin = exists(/databases/$(database)/documents/admins/$(userId));
  return isAuthor || isAdmin;
}

Observe cómo la asignación isAdmin exige una búsqueda de la colección de administradores. Para una evaluación diferida sin requerir búsquedas innecesarias, aproveche la naturaleza de cortocircuito de && (AND) y || (O) comparaciones para llamar a una segunda función solo si se muestra que isAuthor es verdadero (para comparaciones && ) o falso (para comparaciones || ).

function isAdmin(userId) {
  return exists(/databases/$(database)/documents/admins/$(userId));
}
function isAuthorOrAdmin(userId, article) {
  let isAuthor = article.author == userId;
  // `||` is short-circuiting; isAdmin called only if isAuthor == false.
  return isAuthor || isAdmin(userId);
}

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.

Base de datos en tiempo real

Como se describió anteriormente, las reglas de bases de datos en tiempo real incluyen tres elementos básicos: la ubicación de la base de datos como un espejo de la estructura JSON de la base de datos, el tipo de solicitud y la condición que otorga acceso.

Ubicación de la base de datos

La estructura de sus reglas debe seguir la estructura de los datos que ha almacenado en su base de datos. Por ejemplo, en una aplicación de chat con una lista de mensajes, es posible que tenga datos similares a estos:

  {
    "messages": {
      "message0": {
        "content": "Hello",
        "timestamp": 1405704370369
      },
      "message1": {
        "content": "Goodbye",
        "timestamp": 1405704395231
      },
      ...
    }
  }

Tus reglas deben reflejar esa estructura. Por ejemplo:

  {
    "rules": {
      "messages": {
        "$message": {
          // only messages from the last ten minutes can be read
          ".read": "data.child('timestamp').val() > (now - 600000)",

          // new messages must have a string content and a number timestamp
          ".validate": "newData.hasChildren(['content', 'timestamp']) &&
                        newData.child('content').isString() &&
                        newData.child('timestamp').isNumber()"
        }
      }
    }
  }

Como muestra el ejemplo anterior, las reglas de bases de datos en tiempo real admiten una variable $location para hacer coincidir los segmentos de ruta. Utilice el prefijo $ delante de su segmento de ruta para hacer coincidir su regla con cualquier nodo secundario a lo largo de la ruta.

  {
    "rules": {
      "rooms": {
        // This rule applies to any child of /rooms/, the key for each room id
        // is stored inside $room_id variable for reference
        "$room_id": {
          "topic": {
            // The room's topic can be changed if the room id has "public" in it
            ".write": "$room_id.contains('public')"
          }
        }
      }
    }
  }

También puede utilizar la $variable en paralelo con nombres de ruta constantes.

  {
    "rules": {
      "widget": {
        // a widget can have a title or color attribute
        "title": { ".validate": true },
        "color": { ".validate": true },

        // but no other child paths are allowed
        // in this case, $other means any key excluding "title" and "color"
        "$other": { ".validate": false }
      }
    }
  }

Método

En Realtime Database, existen tres tipos de reglas. Dos de estos tipos de reglas ( read y write ) se aplican al método de una solicitud entrante. El tipo de regla validate aplica estructuras de datos y valida el formato y el contenido de los datos. Las reglas ejecutan reglas .validate después de verificar que una regla .write otorga acceso.

Tipos de reglas
.leer Describe si los usuarios pueden leer los datos y cuándo.
.escribir Describe si se permite escribir datos y cuándo.
.validar Define cómo se verá un valor formateado correctamente, si tiene atributos secundarios y el tipo de datos.

De forma predeterminada, si no hay una regla que lo permita, se deniega el acceso a una ruta.

Condiciones de construcción

Tienda de fuego en la nube

Una condición es una expresión booleana que determina si se debe permitir o denegar una operación particular. Las variables request y resource proporcionan contexto para esas condiciones.

La variable request

La variable request incluye los siguientes campos y la información correspondiente:

request.auth

Un token web JSON (JWT) que contiene credenciales de autenticación de Firebase Authentication. El token auth contiene un conjunto de reclamos estándar y cualquier reclamo personalizado que cree a través de Firebase Authentication. Obtenga más información sobre las reglas de seguridad y la autenticación de Firebase .

request.method

El request.method puede ser cualquiera de los métodos estándar o un método personalizado. Los métodos de conveniencia read y write también existen para simplificar las reglas de escritura que se aplican a todos los métodos estándar de solo lectura o de solo escritura, respectivamente.

request.params

request.params incluye cualquier dato que no esté específicamente relacionado con request.resource y que pueda ser útil para la evaluación. En la práctica, este mapa debería estar vacío para todos los métodos estándar y debería contener datos que no sean recursos para los métodos personalizados. Los servicios deben tener cuidado de no cambiar el nombre ni modificar el tipo de ninguna de las claves y valores presentados como parámetros.

request.path

request.path es la ruta del resource de destino. La ruta es relativa al servicio. Los segmentos de ruta que contienen caracteres no seguros para URL, como / están codificados en URL.

La variable resource

El resource es el valor actual dentro del servicio representado como un mapa de pares clave-valor. Hacer referencia a un resource dentro de una condición dará como resultado como máximo una lectura del valor del servicio. Esta búsqueda contará contra cualquier cuota relacionada con el servicio para el recurso. Para las solicitudes get , el resource solo contará para la cuota en caso de denegación.

Operadores y precedencia de operadores

Utilice la siguiente tabla como referencia para los operadores y su precedencia correspondiente en las Reglas para Cloud Firestore y Cloud Storage.

Dadas expresiones arbitrarias a y b , un campo f y un índice i .

Operador Descripción asociatividad
a[i] a() af Índice, llamada, acceso al campo. de izquierda a derecha
!a -a negación unaria De derecha a izquierda
a/ba%ba*b Operadores multiplicativos de izquierda a derecha
a+b ab Operadores aditivos de izquierda a derecha
a>ba>=ba Operadores relacionales de izquierda a derecha
a in b Existencia en lista o mapa de izquierda a derecha
a is type Comparación de tipos, donde type puede ser bool, int, float, número, cadena, lista, mapa, marca de tiempo, duración, ruta o latlng de izquierda a derecha
a==ba!=b Operadores de comparación de izquierda a derecha
a && b Condicional Y de izquierda a derecha
a || b Condicional O de izquierda a derecha
a ? true_value : false_value expresión ternaria de izquierda a derecha

Almacenamiento en la nube

Una condición es una expresión booleana que determina si se debe permitir o denegar una operación particular. Las variables request y resource proporcionan contexto para esas condiciones.

La variable request

La variable request incluye los siguientes campos y la información correspondiente:

request.auth

Un token web JSON (JWT) que contiene credenciales de autenticación de Firebase Authentication. El token auth contiene un conjunto de reclamos estándar y cualquier reclamo personalizado que cree a través de Firebase Authentication. Obtenga más información sobre las reglas de seguridad y la autenticación de Firebase .

request.method

El request.method puede ser cualquiera de los métodos estándar o un método personalizado. Los métodos de conveniencia read y write también existen para simplificar las reglas de escritura que se aplican a todos los métodos estándar de solo lectura o de solo escritura, respectivamente.

request.params

request.params incluye cualquier dato que no esté específicamente relacionado con request.resource y que pueda ser útil para la evaluación. En la práctica, este mapa debería estar vacío para todos los métodos estándar y debería contener datos que no sean recursos para los métodos personalizados. Los servicios deben tener cuidado de no cambiar el nombre ni modificar el tipo de ninguna de las claves y valores presentados como parámetros.

request.path

request.path es la ruta del resource de destino. La ruta es relativa al servicio. Los segmentos de ruta que contienen caracteres no seguros para URL, como / están codificados en URL.

La variable resource

El resource es el valor actual dentro del servicio representado como un mapa de pares clave-valor. Hacer referencia a un resource dentro de una condición dará como resultado como máximo una lectura del valor del servicio. Esta búsqueda contará contra cualquier cuota relacionada con el servicio para el recurso. Para las solicitudes get , el resource solo contará para la cuota en caso de denegación.

Operadores y precedencia de operadores

Utilice la siguiente tabla como referencia para los operadores y su precedencia correspondiente en las Reglas para Cloud Firestore y Cloud Storage.

Dadas expresiones arbitrarias a y b , un campo f y un índice i .

Operador Descripción asociatividad
a[i] a() af Índice, llamada, acceso al campo. de izquierda a derecha
!a -a negación unaria De derecha a izquierda
a/ba%ba*b Operadores multiplicativos de izquierda a derecha
a+b ab Operadores aditivos de izquierda a derecha
a>ba>=ba Operadores relacionales de izquierda a derecha
a in b Existencia en lista o mapa de izquierda a derecha
a is type Comparación de tipos, donde type puede ser bool, int, float, número, cadena, lista, mapa, marca de tiempo, duración, ruta o latlng de izquierda a derecha
a==ba!=b Operadores de comparación de izquierda a derecha
a && b Condicional Y de izquierda a derecha
a || b Condicional O de izquierda a derecha
a ? true_value : false_value expresión ternaria de izquierda a derecha

Base de datos en tiempo real

Una condición es una expresión booleana que determina si se debe permitir o denegar una operación particular. Puede definir esas condiciones en Reglas de bases de datos en tiempo real de las siguientes maneras.

Variables predefinidas

Hay una serie de variables predefinidas útiles a las que se puede acceder dentro de una definición de regla. Aquí hay un breve resumen de cada uno:

Variables predefinidas
ahora La hora actual en milisegundos desde la época de Linux. Esto funciona particularmente bien para validar marcas de tiempo creadas con firebase.database.ServerValue.TIMESTAMP del SDK.
raíz Un RuleDataSnapshot que representa la ruta raíz en la base de datos de Firebase tal como existía antes del intento de operación.
nuevos datos Un RuleDataSnapshot que representa los datos tal como existirían después del intento de operación. Incluye los nuevos datos que se están escribiendo y los datos existentes.
datos Un RuleDataSnapshot que representa los datos tal como existían antes del intento de operación.
$ variables Una ruta comodín utilizada para representar identificadores y claves secundarias dinámicas.
autenticación Representa la carga útil del token de un usuario autenticado.

Estas variables se pueden utilizar en cualquier parte de sus reglas. Por ejemplo, las reglas de seguridad siguientes garantizan que los datos escritos en el nodo /foo/ deben ser una cadena de menos de 100 caracteres:

{
  "rules": {
    "foo": {
      // /foo is readable by the world
      ".read": true,

      // /foo is writable by the world
      ".write": true,

      // data written to /foo must be a string less than 100 characters
      ".validate": "newData.isString() && newData.val().length < 100"
    }
  }
}

Reglas basadas en datos

Cualquier dato de su base de datos se puede utilizar en sus reglas. Usando las variables predefinidas root , data y newData , puede acceder a cualquier ruta tal como existiría antes o después de un evento de escritura.

Considere este ejemplo, que permite operaciones de escritura siempre que el valor del nodo /allow_writes/ sea true , el nodo principal no tenga un indicador readOnly establecido y haya un hijo llamado foo en los datos recién escritos:

".write": "root.child('allow_writes').val() === true &&
          !data.parent().child('readOnly').exists() &&
          newData.child('foo').exists()"

Reglas basadas en consultas

Aunque no puede utilizar reglas como filtros, puede limitar el acceso a subconjuntos de datos utilizando parámetros de consulta en sus reglas. Utilice query. expresiones en sus reglas para otorgar acceso de lectura o escritura según los parámetros de consulta.

Por ejemplo, la siguiente regla basada en consultas utiliza reglas de seguridad basadas en usuarios y reglas basadas en consultas para restringir el acceso a los datos en la colección de baskets solo a las cestas de compras que posee el usuario activo:

"baskets": {
  ".read": "auth.uid !== null &&
            query.orderByChild === 'owner' &&
            query.equalTo === auth.uid" // restrict basket access to owner of basket
}

La siguiente consulta, que incluye los parámetros de consulta de la regla, tendría éxito:

db.ref("baskets").orderByChild("owner")
                 .equalTo(auth.currentUser.uid)
                 .on("value", cb)                 // Would succeed

Sin embargo, las consultas que no incluyen los parámetros de la regla generarían un error PermissionDenied :

db.ref("baskets").on("value", cb)                 // Would fail with PermissionDenied

También puede utilizar reglas basadas en consultas para limitar la cantidad de datos que descarga un cliente mediante operaciones de lectura.

Por ejemplo, la siguiente regla limita el acceso de lectura solo a los primeros 1000 resultados de una consulta, ordenados por prioridad:

messages: {
  ".read": "query.orderByKey &&
            query.limitToFirst <= 1000"
}

// Example queries:

db.ref("messages").on("value", cb)                // Would fail with PermissionDenied

db.ref("messages").limitToFirst(1000)
                  .on("value", cb)                // Would succeed (default order by key)

La siguiente query. Las expresiones están disponibles en Reglas de seguridad de bases de datos en tiempo real.

Expresiones de reglas basadas en consultas
Expresión Tipo Descripción
consulta.orderByKey
consulta.orderByPriority
consulta.orderByValue
booleano Verdadero para consultas ordenadas por clave, prioridad o valor. Falso en caso contrario.
consulta.orderByChild cadena
nulo
Utilice una cadena para representar la ruta relativa a un nodo secundario. Por ejemplo, query.orderByChild === "address/zip" . Si la consulta no está ordenada por un nodo secundario, este valor es nulo.
consulta.startAt
consulta.endAt
consulta.equalTo
cadena
número
booleano
nulo
Recupera los límites de la consulta en ejecución o devuelve nulo si no hay ningún límite establecido.
consulta.limitToFirst
consulta.limitToLast
número
nulo
Recupera el límite de la consulta en ejecución o devuelve nulo si no hay ningún límite establecido.

Operadores

Las reglas de bases de datos en tiempo real admiten varios operadores que puede utilizar para combinar variables en la declaración de condición. Consulte la lista completa de operadores en la documentación de referencia .

Creando condiciones

Sus condiciones reales variarán según el acceso que desee otorgar. Las reglas ofrecen intencionalmente un enorme grado de flexibilidad, por lo que, en última instancia, las reglas de su aplicación pueden ser tan simples o complejas como usted necesite.

Para obtener orientación sobre la creación de reglas simples y listas para producción, consulte Reglas de seguridad básicas .