API de reglas de seguridad de la base de datos de Firebase

Regla: tipos

.leer

Otorga a un cliente acceso de lectura a una ubicación de Firebase Realtime Database.

Una regla .read es un tipo de regla de seguridad que otorga a un cliente acceso de lectura a una ubicación de Firebase Realtime Database. Por ejemplo:

 ".read": "auth != null && auth.provider == 'twitter'"

El valor de una regla .read es una cadena, que se evalúa como un subconjunto de la sintaxis de expresión de JavaScript con algunos cambios de comportamiento para aumentar la claridad y la corrección. Una regla .read que otorga permiso para leer una ubicación también permitirá la lectura de cualquier descendiente de esa ubicación, incluso si los descendientes tienen sus propias reglas .read que fallan.

Una regla .read tiene acceso a todas las variables de regla de Firebase Realtime Database excepto newData .

.escribir

Otorga a un cliente acceso de escritura a una ubicación de Firebase Realtime Database.

Una regla .write es un tipo de regla de seguridad que otorga a un cliente acceso de escritura a una ubicación de Firebase Realtime Database. Por ejemplo:

".write": "auth != null && auth.token.isAdmin == true"

El valor de una regla .write es una cadena, que se evalúa como un subconjunto de la sintaxis de expresión de JavaScript con algunos cambios de comportamiento para aumentar la claridad y la corrección. Una regla .write que otorga permiso para escribir en una ubicación también permitirá escribir a cualquier descendiente de esa ubicación, incluso si los descendientes tienen sus propias reglas .write que fallan.

Una regla .write tiene acceso a todas las variables de reglas de Firebase Realtime Database.

.validar

Se utiliza una vez que una regla .write ha otorgado acceso, para garantizar que los datos que se escriben se ajusten a un esquema específico.

Una regla .validate se utiliza una vez que una regla .write ha otorgado acceso, para garantizar que los datos que se escriben cumplan con un estándar específico. Además de que un .write otorgue acceso, todas las reglas .validate relevantes deben tener éxito antes de que se permita una escritura. Por ejemplo:

".validate": "newData.hasChildren(['name', 'age'])"

El valor de una regla .validate es una cadena, que se evalúa como un subconjunto de la sintaxis de expresión de JavaScript con algunos cambios de comportamiento para aumentar la claridad y la corrección.

Una regla .validate tiene acceso a todas las variables de reglas de Firebase Realtime Database.

.indexOn

Mejora el rendimiento de las consultas al indicarle a Firebase Realtime Database qué claves desea que se indexen sus datos.

La regla .indexOn indica a los servidores de Firebase Realtime Database que indexen claves específicas en sus datos para mejorar el rendimiento de sus consultas. Por ejemplo, dada una base de datos con una colección de datos de dinosaurios, podemos decirle a Firebase Realtime Database que optimice las consultas, antes de que sean devueltas desde los servidores, agregando esta regla:

{
  "rules": {
    "dinosaurs": {
      ".indexOn": ["height", "length"]
    }
  }
}

Puede encontrar más información sobre la regla .indexOn consultando la sección de la guía de seguridad sobre indexación de sus datos .

Regla: variables

autenticación

Una variable que contiene la carga útil del token si un cliente está autenticado, o null si el cliente no está autenticado.

Firebase Realtime Database le permite autenticarse fácilmente en varios proveedores integrados y generará tokens de autenticación para ellos. Después de que un usuario se autentique con uno de los proveedores integrados, la variable de autenticación contendrá lo siguiente:

Campo Descripción
provider El método de autenticación utilizado (por ejemplo, "contraseña", "anónimo", "facebook", "github", "google" o "twitter").
uid Una identificación de usuario única, garantizada para ser única en todos los proveedores.
token El contenido del token de ID de autenticación de Firebase. Consulte auth.token .

Como ejemplo, podríamos tener una regla como la siguiente para permitir a los usuarios crear comentarios siempre que almacenen su ID de usuario con el comentario:

{
  "rules": {
    ".read": true,
    "$comment": {
      ".write": "!data.exists() && newData.child('user_id').val() == auth.uid"
    }
  }
}

También podríamos establecer una regla como la siguiente para permitir a los usuarios crear comentarios siempre que hayan iniciado sesión con Facebook:

{
  "rules": {
    ".read": true,
    "$comment": {
      ".write": "!data.exists() && auth.provider == 'facebook'"
    }
  }
}

token de autenticación

Una variable que contiene el contenido del token de ID de autenticación de Firebase.

El token contiene algunas o todas las siguientes claves:

Campo Descripción
email La dirección de correo electrónico asociada con la cuenta, si está presente.
email_verified true si el usuario ha verificado que tiene acceso a la dirección email . Algunos proveedores verifican automáticamente las direcciones de correo electrónico de su propiedad.
phone_number El número de teléfono asociado con la cuenta, si está presente.
name El nombre para mostrar del usuario, si está configurado.
sub El UID de Firebase del usuario. Esto es único dentro de un proyecto.
firebase.identities Diccionario de todas las identidades que están asociadas a la cuenta de este usuario. Las claves del diccionario pueden ser cualquiera de las siguientes: email , phone , google.com , facebook.com , github.com , twitter.com . Los valores del diccionario son matrices de identificadores únicos para cada proveedor de identidad asociado con la cuenta. Por ejemplo, auth.token.firebase.identities["google.com"][0] contiene el primer ID de usuario de Google asociado con la cuenta.
firebase.sign_in_provider El proveedor de inicio de sesión utilizado para obtener este token. Puede ser una de las siguientes cadenas: custom , password , phone , anonymous , google.com , facebook.com , github.com , twitter.com .
firebase.tenant El ID de inquilino asociado con la cuenta, si está presente. por ejemplo, tenant2-m6tyz

Si utiliza autenticación personalizada, auth.token también contiene cualquier reclamo personalizado especificado por el desarrollador.

Todos estos valores se pueden utilizar dentro de las reglas. Por ejemplo, para restringir el acceso a cuentas de Google asociadas a una dirección de gmail.com, podríamos agregar la regla:

{
  "rules": {
    ".read": "auth != null",
    "gmailUsers": {
      "$uid": {
        ".write": "auth.token.email_verified == true && auth.token.email.matches(/.*@gmail.com$/)"
      }
    }
  }
}

Para completar, también se incluyen los siguientes campos en auth.token , pero es poco probable que sean útiles para las reglas.

Campo Descripción
iss El emisor del token.
aud La audiencia del token.
auth_time La última vez que el usuario se autenticó con una credencial utilizando el dispositivo que recibió el token.
iat La hora a la que se emitió el token.
exp La hora a la que caduca el token.

$ubicación

Una variable que se puede usar para hacer referencia a la clave de una $location que se usó anteriormente en una estructura de reglas.

Cuando tiene una $location en su estructura de reglas, puede usar una variable $ coincidente dentro de su expresión de regla para obtener el nombre del niño real que se está leyendo o escribiendo. Entonces supongamos que queremos darle a cada usuario acceso de lectura y escritura a su propia ubicación /users/<user> . Podríamos usar:

{
  "rules": {
    "users": {
      "$user": {
        ".read": "auth.uid === $user",
        ".write": "auth.uid === $user"
      }
    }
  }
}

Cuando un cliente intenta acceder a /users/barney , la ubicación predeterminada $user coincidirá con $user igual a "barney". Entonces la regla .read verificará si auth.uid === 'barney' . Como resultado, la lectura /users/barney será exitosa sólo si el cliente está autenticado con un uid de "barney".

ahora

Contiene la cantidad de milisegundos desde la época de Unix según los servidores de Firebase Realtime Database.

La variable now contiene la cantidad de milisegundos desde la época UNIX según los servidores de Firebase Realtime Database. Por ejemplo, podrías usar esto para validar que la hora created de un usuario nunca se establezca en una hora futura:

{
  "rules": {
    "users": {
      "$user": {
        "created": {
          ".validate": "newData.val() < now"
        }
      }
    }
  }
}

raíz

Una RuleDataSnapshot correspondiente a los datos actuales en la raíz de su Firebase Realtime Database.

La variable raíz le proporciona una RuleDataSnapshot correspondiente a los datos actuales en la raíz de su Firebase Realtime Database. Puede usar esto para leer cualquier dato en su base de datos en sus expresiones de regla. Por ejemplo, si quisiéramos permitir a los usuarios leer /comments solo si su /users/<id>/active está configurado en verdadero, podríamos usar:

{
  "rules": {
    "comments": {
      ".read": "root.child('users').child(auth.uid).child('active').val() == true"
    }
  }
}

Entonces, si /users/barney/active contenía el valor verdadero, un usuario autenticado con un uid de "barney" podría escribir en el nodo /comments .

datos

Una RuleDataSnapshot correspondiente a los datos actuales en Firebase Realtime Database en la ubicación de la regla que se está ejecutando actualmente.

La variable de datos le proporciona una RuleDataSnapshot correspondiente a los datos actuales en la ubicación de la base de datos de la regla que se está ejecutando actualmente (a diferencia de root, que le proporciona los datos para la raíz de su base de datos).

Entonces, por ejemplo, si desea permitir que cualquier cliente acceda a /users/<user> si /users/<user>/public está configurado en verdadero, puede usar:

{
  "rules": {
    "users": {
      "$user": {
        ".read": "data.child('public').val() == true"
      }
    }
  }
}

La variable de datos está disponible en reglas .read , .write y .validate .

nuevos datos

Un RuleDataSnapshot correspondiente a los datos que resultarán si se permite la escritura.

Para las reglas .write y .validate , la variable newData le proporciona una RuleDataSnapshot correspondiente a los datos que resultarán si se permite la escritura (es una "fusión" de los datos existentes más los nuevos datos que se están escribiendo). Entonces, si quisieras asegurarte de que cada usuario tenga un nombre y una edad, podrías usar:

{
  "rules": {
    "users": {
      "$user": {
        ".read": true,
        ".write": true,
        ".validate": "newData.hasChildren(['name', 'age'])"
      }
    }
  }
}

Dado que newData fusiona datos existentes y datos nuevos, se comporta correctamente incluso para actualizaciones "parciales". Por ejemplo:

var fredRef = firebase.database().ref("users/fred");
// Valid since we have a name and age.
fredRef.set({ name: "Fred", age: 19 });
// Valid since we are updating the name but there's already an age.
fredRef.child("age").set(27);
// Invalid since the .validate rule will no longer be true.
fredRef.child("name").remove();

La variable newData no está disponible en las reglas .read ya que no se escriben datos nuevos. Sólo deberías usar datos .

RuleDataSnapshot: métodos

valor()

Obtiene el valor primitivo ( string , number , boolean o null ) de este RuleDataSnapshot .

Valor de retorno : ( String , Number , Boolean , Null ): el valor primitivo de esta RuleDataSnapshot .

A diferencia de DataSnapshot.val() , llamar val() en un RuleDataSnapshot que tiene datos secundarios no devolverá un objeto que contenga los elementos secundarios. En su lugar, devolverá un valor centinela especial. Esto garantiza que las reglas siempre puedan funcionar de manera extremadamente eficiente.

Como consecuencia, siempre debes usar child() para acceder a los niños (por ejemplo data.child('name').val() , no data.val().name ).

Este ejemplo solo permite la lectura si el elemento secundario isReadable está establecido en verdadero en la ubicación que se está leyendo.

".read": "data.child('isReadable').val() == true"

niño()

Obtiene un RuleDataSnapshot para la ubicación en la ruta relativa especificada.

Argumentos : childPath String : una ruta relativa a la ubicación de los datos secundarios.

Valor de retorno : RuleDataSnapshot : RuleDataSnapshot para la ubicación secundaria.

La ruta relativa puede ser un simple nombre de niño (por ejemplo, 'fred') o una ruta más profunda separada por barras (por ejemplo, 'fred/nombre/primero'). Si la ubicación secundaria no tiene datos, se devuelve un RuleDataSnapshot vacío.

Este ejemplo solo permite la lectura si el elemento secundario isReadable está establecido en verdadero en la ubicación que se está leyendo.

".read": "data.child('isReadable').val() == true"

padre()

Obtiene una RuleDataSnapshot para la ubicación principal.

Valor de retorno : RuleDataSnapshot : RuleDataSnapshot para la ubicación principal.

Si esta instancia hace referencia a la raíz de su Firebase Realtime Database, no tiene padre y parent() fallará, lo que provocará que se omita la expresión de regla actual (como un error).

Este ejemplo solo permite la lectura si el hermano isReadable está configurado en verdadero.

".read": "data.parent().child('isReadable').val() == true"

tieneniño(rutaniño)

Devuelve verdadero si el hijo especificado existe.

Argumentos : childPath String : una ruta relativa a la ubicación de un niño potencial.

Valor de retorno : booleano : true si existen datos en la ruta secundaria especificada; de lo contrario false .

Este ejemplo solo permite escribir los datos si contienen un "nombre" secundario.

".validate": "newData.hasChild('name')"

tieneNiños([niños])

Comprueba la existencia de niños.

Argumentos : Array children opcional : una matriz de claves secundarias que deben existir.

Valor de retorno : Boolean : true si existen los hijos (especificados); de lo contrario false .

Si no se proporcionan argumentos, devolverá verdadero si RuleDataSnapshot tiene hijos. Si se proporciona una matriz de nombres de niños, devolverá verdadero solo si todos los niños especificados existen en RuleDataSnapshot .

Este ejemplo solo permite escribir los datos si contienen uno o más hijos.

".validate": "newData.hasChildren()"

Este ejemplo solo permite escribir los datos si contienen niños de "nombre" y "edad".

".validate": "newData.hasChildren(['name', 'age'])"

existe()

Devuelve verdadero si este RuleDataSnapshot contiene datos.

Valor de retorno : Boolean : true si RuleDataSnapshot contiene datos; de lo contrario false .

La función existe devuelve verdadero si este RuleDataSnapshot contiene datos. Es una función puramente de conveniencia ya que data.exists() es equivalente a data.val() != null .

Este ejemplo permite escribir en esta ubicación siempre que no existan datos.

".write": "!data.exists()"

obtenerPrioridad()

Obtiene la prioridad de los datos en RuleDataSnapshot .

Valor de retorno : ( String , Number , Null ): la prioridad de los datos en este RuleDataSnapshot .

Este ejemplo garantiza que los nuevos datos que se escriben tengan prioridad.

".validate": "newData.getPriority() != null"

es número()

Devuelve verdadero si este RuleDataSnapshot contiene un valor numérico.

Valor de retorno : Boolean : true si los datos son numéricos; de lo contrario false .

Este ejemplo garantiza que los nuevos datos que se escriben tengan una "edad" secundaria con un valor numérico.

".validate": "newData.child('age').isNumber()"

esCadena()

Devuelve verdadero si este RuleDataSnapshot contiene un valor de cadena.

Valor de retorno : Boolean - true si los datos son una String ; de lo contrario false .

Este ejemplo garantiza que los nuevos datos que se escriben tengan un "nombre" secundario con un valor de cadena.

".validate": "newData.child('name').isString()

es booleano()

Devuelve verdadero si este RuleDataSnapshot contiene un valor booleano.

Valor de retorno : Boolean : true si los datos son Boolean ; de lo contrario false .

Este ejemplo garantiza que los nuevos datos que se escriben tengan un elemento secundario "activo" con un valor booleano.

".validate": "newData.child('active').isBoolean()"

Cadena: Propiedades

longitud

Devuelve la longitud de la cadena.

Valor de retorno : Number : el número de caracteres de la cadena.

Este ejemplo requiere que la cadena tenga al menos 10 caracteres.

".validate": "newData.isString() && newData.val().length >= 10"

Cadena: Métodos

contiene (subcadena)

Devuelve verdadero si la cadena contiene la subcadena especificada.

Argumentos : substring String : una subcadena a buscar.

Valor de retorno : Boolean : true si la cadena contiene la subcadena especificada; de lo contrario false .

Este ejemplo requiere que los datos sean una cadena que contenga "@".

".validate": "newData.isString() && newData.val().contains('@')"

comienza con (subcadena)

Devuelve verdadero si la cadena comienza con la subcadena especificada.

Argumentos : substring String : una subcadena que se buscará al principio.

Valor de retorno : Boolean : true si la cadena contiene la subcadena especificada; de lo contrario false .

Este ejemplo permite acceso de lectura si auth.token.identifier comienza con "internal-"

".read": "auth.token.identifier.beginsWith('internal-')"

termina con (subcadena)

Devuelve verdadero si la cadena termina con la subcadena especificada.

Argumentos : substring String : una subcadena que se buscará al final.

Valor de retorno : Boolean : true si la cadena termina con la subcadena especificada; de lo contrario false .

Este ejemplo permite acceso de lectura si auth.token.identifier termina en "@empresa.com"

".read": "auth.token.identifier.endsWith('@company.com')"

reemplazar (subcadena, reemplazo)

Devuelve una copia de la cadena con todas las instancias de una subcadena especificada reemplazadas por la cadena de reemplazo especificada.

Argumentos : substring String : una subcadena a buscar. replacement String : una cadena con la que reemplazar la subcadena.

Valor de retorno : String : la nueva cadena después de reemplazar la subcadena con reemplazo.

El método replace() difiere ligeramente del método replace() de JavaScript en que reemplaza todas las instancias de una subcadena especificada con la cadena de reemplazo especificada, no solo la primera instancia.

Dado que no se permiten puntos en las claves, debemos escapar las cadenas con puntos antes de almacenarlas. Un ejemplo de esto sería con las direcciones de correo electrónico. Supongamos que tenemos una lista de direcciones de correo electrónico incluidas en la lista blanca en nuestro nodo /whitelist/ :

{
 "user": {
   "$uid": {
     "email": <email>
   }
 },
 "whitelist": {
   "fred@gmail%2Ecom": true,
   "barney@aol%2Ecom": true
 }
}

Podemos crear una regla que solo permita agregar usuarios si su correo electrónico está en el nodo /whitelist/ :

{
  "rules": {
    "users": {
      "$uid": {
        ".read": "true",
        ".write": "root.child('whitelist').child(newData.child('email').val().replace('.', '%2E')).exists()"
      }
    }
  }
}

a minúsculas()

Devuelve una copia de la cadena convertida a minúsculas.

Valor de retorno : String : la cadena convertida a minúsculas.

Este ejemplo permite acceso de lectura si auth.token.identifier ya que todo está en minúsculas en /users .

".read": "root.child('users').child(auth.token.identifier.toLowerCase()).exists()"

a mayúsculas()

Devuelve una copia de la cadena convertida a mayúsculas.

Valor de retorno : String : la cadena convertida a mayúsculas.

Este ejemplo permite acceso de lectura si auth.token.identifier ya que todas las mayúsculas existen en /users .

".read": "root.child('users').child(auth.token.identifier.toUpperCase()).exists()"

coincidencias (expresión regular)

Devuelve verdadero si la cadena coincide con el literal de expresión regular especificado.

Valor de retorno : Boolean : true si la cadena coincide con la expresión regular literal, regex; de lo contrario false .

Consulte la documentación completa de reglas de expresiones regulares .

Operadores

+ (añadir)

Se utiliza para agregar variables o para concatenación de cadenas.

El siguiente ejemplo garantiza que el nuevo valor incremente el valor existente exactamente en uno. Esto es útil para implementar un contador:

".write": "newData.val() === data.val() + 1"
".validate": "root.child('room_names/' + $room_id).exists()"

- (negar o restar)

Se utiliza para negar un valor o restar dos valores en una expresión de reglas.

Esta regla de validación verifica que el nuevo valor sea el inverso de un valor secundario en la ubicación:

".validate": "newData.val() === -(data.child('quantity').val())"

El siguiente ejemplo utiliza la resta para garantizar que solo se puedan leer los mensajes de los últimos diez minutos:

".read": "newData.child('timestamp').val() > (now - 600000)"

* (multiplicar)

Se utiliza para multiplicar variables en una expresión de reglas.

Esta regla de validación verifica si el nuevo valor es igual al producto de precio y cantidad (dos valores existentes):

".validate": "newData.val() === data.child('price').val() * data.child('quantity').val()"

/ (dividir)

Se utiliza para dividir variables en una expresión de reglas.

En el siguiente ejemplo, la regla de validación garantiza que los datos almacenados sean el promedio del total de datos almacenados en otro lugar:

".validate": "newData.val() === data.parent().child('sum').val() / data.parent().child('numItems').val()"

% (módulo)

Se utiliza para encontrar el resto de dividir una variable entre otra en una expresión de reglas.

Esta regla valida que sólo se pueden escribir números pares:

".validate": "newData.val() % 2 === 0"

=== (igual)

Se utiliza para comprobar si dos variables en una expresión de reglas tienen el mismo tipo y valor.

La siguiente regla utiliza el operador === para otorgar acceso de escritura solo al propietario de la cuenta de usuario. El uid del usuario debe coincidir exactamente con la clave ( $user_id ) para que la regla se evalúe como verdadera.

"users": {
  ".write": "$user_id === auth.uid"
}

!== (no es igual)

Se utiliza para comprobar si dos variables en una expresión de reglas no son iguales.

La siguiente regla de lectura garantiza que solo los usuarios que hayan iniciado sesión puedan leer los datos:

".read": "auth !== null"

&& (Y)

Se evalúa como verdadero si ambos operandos son verdaderos. Se utiliza para evaluar múltiples condiciones en una expresión de reglas.

La siguiente regla de validación verifica que los nuevos datos sean una cadena de menos de 100 caracteres:

".validate": "newData.isString() && newData.val().length < 100"

|| (O)

Se evalúa como verdadero si un operando en la expresión de reglas es verdadero.

En este ejemplo, podemos escribir siempre que no existan datos antiguos o nuevos. En otras palabras, podemos escribir si estamos eliminando o creando datos, pero no actualizando datos.

".write": "!data.exists() || !newData.exists()"

! (NO)

Se evalúa como verdadero si su único operando es falso. En expresiones de reglas, el ! El operador se utiliza a menudo para ver si se han escrito datos en una ubicación.

La siguiente regla solo permite acceso de escritura si no hay datos en la ubicación especificada:

".write": "!data.exists()"

> (mayor que)

Se utiliza para comprobar si un valor es mayor que otro valor en una expresión de reglas.

Esta regla de validación verifica que la cadena que se escribe no sea una cadena vacía:

".validate": "newData.isString() && newData.val().length > 0"

< (menos que)

Se utiliza para comprobar si un valor es menor que otro valor en una expresión de reglas.

Esta regla de validación verifica que una cadena tenga menos de 20 caracteres:

".validate": "newData.isString() && newData.val().length < 20"

>= (mayor o igual a)

Se utiliza para comprobar si un valor es mayor o igual que otro valor en una expresión de reglas.

Esta regla de validación verifica que la cadena que se escribe no sea una cadena vacía:

".validate": "newData.isString() && newData.val().length >= 1"

<= (menor o igual a)

Se utiliza para comprobar si un valor es menor o igual que otro valor en una expresión de reglas.

Esta regla de validación garantiza que no se puedan agregar nuevos datos en el futuro:

".validate": "newData.val() <= now"

? (operador ternario)

Se utiliza para evaluar una expresión de reglas condicionales.

El operador ternario toma tres operandos. ¿El operando antes del? es la condición. Si la condición se evalúa como verdadera, se evalúa el segundo operando. Si la condición es falsa, se evalúa el tercer operando.

Para la siguiente regla de validación, el nuevo valor puede ser un número o un valor booleano. Si es un número, debe ser mayor que 0.

".validate": "newData.isNumber() ? newData.val() > 0 : newData.isBoolean()"