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 .

.escribe

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 en 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 regla de Firebase Realtime Database.

.validar

Se usa 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 usa una vez que una regla .write ha otorgado acceso, para garantizar que los datos que se escriben se ajusten a un estándar específico. Además de un .write que otorga acceso, todas las reglas relevantes .validate 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 regla de Firebase Realtime Database.

.indexOn

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

La regla .indexOn le dice 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 las devuelvan 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 la indexación de sus datos .

Regla: Variables

autenticación

Una variable que contiene la carga 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 autentica 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. Ver auth.token .

Como ejemplo, podríamos tener una regla como la siguiente para permitir que los usuarios creen 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 crear 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'"
    }
  }
}

auth.token

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 de email . Algunos proveedores verifican automáticamente las direcciones de correo electrónico que poseen.
phone_number El número de teléfono asociado con la cuenta, si está presente.
name El nombre para mostrar del usuario, si está establecido.
sub El UID de Firebase del usuario. Esto es único dentro de un proyecto.
firebase.identities Diccionario de todas las identidades 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 TenantId asociado con la cuenta, si está presente. por ejemplo tenant2-m6tyz

Si usa la autenticación personalizada, auth.token también contiene las notificaciones personalizadas especificadas por el desarrollador.

Todos estos valores se pueden utilizar dentro de las reglas. Por ejemplo, para restringir el acceso a las 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, los siguientes campos también se incluyen en auth.token , pero es poco probable que sean útiles para las reglas.

Campo Descripción
iss El emisor del token.
aud La audiencia para el token.
auth_time La última vez que el usuario se autenticó con una credencial utilizando el dispositivo que recibe el token.
iat El momento en 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 regla.

Cuando tiene una $location en su estructura de reglas, puede usar una variable de $ coincidente dentro de su expresión de regla para obtener el nombre del niño real que se lee o escribe. Así que supongamos que queremos dar 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 de $user coincidirá con $user igual a "barney". Entonces, la regla .read verificará si auth.uid === 'barney' . Como resultado, la lectura de /users/barney solo tendrá éxito 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 de UNIX según los servidores de Firebase Realtime Database. Por ejemplo, podría usar esto para validar que la hora de created de un usuario nunca se establece en una hora en el futuro:

{
  "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 brinda un RuleDataSnapshot correspondiente a los datos actuales en la raíz de su base de datos en tiempo real de Firebase. Puede usar esto para leer cualquier dato en su base de datos en sus expresiones de regla. Por ejemplo, si quisiéramos permitir que los usuarios leyeran /comments solo si su /users/<id>/active se estableció en verdadero, podríamos usar:

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

Luego, 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 brinda un 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 brinda 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 se estableció en verdadero, podría usar:

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

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

nuevos datos

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

Para las reglas .write y .validate , la variable newData le brinda 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 escriben). Entonces, si quisiera asegurarse de que cada usuario tenga un nombre y una edad, podría usar:

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

Dado que newData combina 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 están escribiendo nuevos datos. Solo debes usar datos .

RuleDataSnapshot: Métodos

valor()

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

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

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

Como consecuencia, siempre debe 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 se establece en verdadero en la ubicación que se lee.

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

niño()

Obtiene una 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 nombre de niño simple (p. ej., 'fred') o una ruta más profunda separada por barras (p. ej., 'fred/name/first'). Si la ubicación secundaria no tiene datos, se devuelve una RuleDataSnapshot vacía.

Este ejemplo solo permite la lectura si el elemento secundario isReadable se establece en verdadero en la ubicación que se lee.

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

padre()

Obtiene una RuleDataSnapshot para la ubicación principal.

Valor devuelto: RuleDataSnapshot : la RuleDataSnapshot para la ubicación principal.

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

Este ejemplo solo permite la lectura si el hermano isReadable se establece en verdadero.

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

hasChild (ruta del niño)

Devuelve verdadero si el hijo especificado existe.

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

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

Este ejemplo solo permite que los datos se escriban si contienen un "nombre" secundario.

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

tieneHijos([hijos])

Comprueba la existencia de hijos.

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

Valor de retorno : Boolean : true si (los especificados) hijos existen; 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 que los datos se escriban si contienen uno o más hijos.

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

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

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

existe()

Devuelve verdadero si esta RuleDataSnapshot contiene datos.

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

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

Este ejemplo permite una escritura en esta ubicación siempre que no haya datos existentes.

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

obtenerPrioridad()

Obtiene la prioridad de los datos en RuleDataSnapshot .

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

Este ejemplo asegura que los nuevos datos que se escriben tienen prioridad

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

es número()

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

Valor devuelto: 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 esta RuleDataSnapshot contiene un valor de cadena.

Valor devuelto: 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()

esBooleano()

Devuelve verdadero si esta 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 hijo "activo" con un valor booleano.

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

Cadena: Propiedades

longitud

Devuelve la longitud de la cadena.

Valor devuelto : Number : el número de caracteres en 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 para 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 para buscar al principio.

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

Este ejemplo permite el 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 para buscar al final.

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

Este ejemplo permite el acceso de lectura si auth.token.identifier termina en "@company.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 reemplazada por la cadena de reemplazo especificada.

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

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

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

Dado que los puntos no están permitidos en las claves, debemos escapar de las cadenas con puntos antes de almacenarlas. Un ejemplo de esto sería con las direcciones de correo electrónico. Supongamos que teníamos 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()"
      }
    }
  }
}

aLowerCase()

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

Valor devuelto: String : la cadena convertida a minúsculas.

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

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

aMayúsculas()

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

Valor devuelto: String : la cadena convertida a mayúsculas.

Este ejemplo permite el 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 (regex)

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

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

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

Operadores

+ (añadir)

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

El siguiente ejemplo asegura que el nuevo valor incrementa 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 del precio y la 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 se asegura de 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 por otra en una expresión de reglas.

Esta regla valida que solo se pueden escribir números pares:

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

=== (igual)

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

La siguiente regla usa 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 registrados puedan leer 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 datos 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 las expresiones de reglas, el ! El operador se usa a menudo para ver si los datos se han escrito en una ubicación.

La siguiente regla solo permite el 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"

< (menor que)

Se utiliza para verificar 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 que)

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 que)

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()"