Referencia de las reglas de seguridad de Firebase para el almacenamiento en la nube

Las reglas de seguridad de Firebase para Cloud Storage se utilizan para determinar quién tiene acceso de lectura y escritura a los archivos almacenados en Cloud Storage, así como también cómo se estructuran los archivos y qué metadatos contienen. Las reglas de seguridad de Cloud Storage se componen de reglas que consideran la request y resource para permitir o denegar una acción deseada, como cargar un archivo o recuperar metadatos de un archivo. Estos documentos de referencia cubren los tipos de reglas, las propiedades de una request y un resource , los tipos de datos utilizados por las reglas de seguridad de Cloud Storage y cómo ocurren los errores.

Regla

Una rule es una expresión que se evalúa para determinar si una request puede realizar una acción deseada.

Tipos

Permitir

Las reglas allow constan de un método, como read o write , así como una condición opcional. Cuando se ejecuta una regla, se evalúa la condición y, si la condición se evalúa como true , se permite el método deseado; de lo contrario, se rechaza el método. Una regla allow sin condición siempre permite el método deseado.

// Always allow method
allow <method>;

// Allow method if condition is true
allow <method>: if <condition>;

Actualmente, allow es el único tipo de regla admitido.

Métodos de solicitud

Leer

El método read cubre todas las solicitudes en las que se leen datos o metadatos de archivos, incluidas las descargas de archivos y las lecturas de metadatos de archivos.

// Always allow reads
allow read;

// Allow reads if condition evaluates to true
allow read: if <condition>;

Escribir

El método write cubre todas las solicitudes en las que se escriben datos o metadatos de archivos, incluidas la carga y eliminación de archivos y las actualizaciones de metadatos de archivos.

// Always allow writes
allow write;

// Allow writes if condition evaluates to true
allow write: if <condition>;

Fósforo

Las reglas se ejecutan cuando la request de un usuario (como la carga o descarga de un archivo) coincide con una ruta de archivo cubierta por una regla. Una match consta de una ruta y un cuerpo, que deben contener al menos una regla allow . Si no coincide ninguna ruta, la solicitud se rechaza.

Puede match una ruta con el nombre completo o puede insertar comodines para hacer coincidir todas las rutas que se ajusten a un patrón determinado.

Segmentos de ruta

single_segment

Puedes usar segmentos de ruta única para crear una regla que coincida con un archivo almacenado en Cloud Storage.

// Allow read at "path" if condition evaluates to true
match /path {
  allow read: if <condition>;
}

También se permiten múltiples segmentos de ruta y rutas anidadas:

// Allow read at "path/to/object" if condition evaluates to true
match /path {
  match /to {
    match /object {
      allow read: if <condition>;
    }
  }
}

{single_segment_wildcard}

Si desea aplicar una regla a varios archivos en la misma ruta, puede utilizar un segmento de ruta comodín para hacer coincidir todos los archivos en una ruta determinada. 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 de coincidencia como una string .

// Allow read at any path "/*", if condition evaluates to true
match /{single_path} {
  // Matches "path", "to", or "object" but not "path/to/object"
  allow read: if <condition>;
}

Varios segmentos de ruta y rutas anidadas también pueden tener comodines:

// Allow read at any path "/path/*/newPath/*", if condition evaluates to true
match /path/{first_wildcard} {
  match /newPath/{second_wildcard} {
    // Matches "path/to/newPath/newObject" or "path/from/newPath/oldObject"
    allow read: if <condition>;
  }
}

{multi_segment_wildcard=**}

Si desea hacer coincidir cualquier número de segmentos de ruta en una ruta o debajo de ella, puede usar un comodín de múltiples segmentos, que hará coincidir todas las solicitudes hasta la ubicación y debajo de ella. Esto puede resultar útil para proporcionar a un usuario su propio espacio de almacenamiento de formato libre o crear reglas que coincidan con muchos segmentos de ruta diferentes (como crear un conjunto de archivos legibles públicamente o requerir autenticación para todas las escrituras).

Una ruta comodín de varios segmentos se declara de manera similar a un comodín de un solo segmento, con la adición de =** al final de la variable: {variable=**} . Una variable comodín de múltiples segmentos está disponible dentro de la declaración de coincidencia como un objeto path .

// Allow read at any path "/**", if condition evaluates to true
match /{multi_path=**} {
  // Matches anything at or below this, from "path", "path/to", "path/to/object", ...
  allow read: if <condition>;
}

Pedido

La variable request se proporciona dentro de una condición para representar la solicitud que se realiza en esa ruta. La variable request tiene una serie de propiedades que se pueden utilizar para decidir si se permite la solicitud entrante.

Propiedades

auth

Cuando un usuario autenticado realiza una solicitud en Cloud Storage, la variable auth se completa con el uid del usuario ( request.auth.uid ), así como con las reclamaciones del JWT de autenticación de Firebase ( request.auth.token ).

request.auth.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, request.auth.token también contiene cualquier reclamo personalizado especificado por el desarrollador.

Cuando un usuario no autenticado realiza una solicitud, request.auth es null .

// Allow requests from authenticated users
allow read, write: if request.auth != null;

path

La variable path contiene la ruta en la que se realiza una request .

// Allow a request if the first path segment equals "images"
allow read, write: if request.path[0] == 'images';

resource

La variable resource contiene los metadatos de un archivo que se está cargando o los metadatos actualizados de un archivo existente. Esto está relacionado con la variable resource , que contiene los metadatos del archivo actual en la ruta solicitada, a diferencia de los nuevos metadatos.

// Allow a request if the new value is smaller than 5MB
allow read, write: if request.resource.size < 5 * 1024 * 1024;

request.resource contiene las siguientes propiedades del resource :

Propiedad
name
bucket
metadata
size
contentType

time

La variable time contiene una marca de tiempo que representa la hora actual del servidor en la que se evalúa una solicitud. Puede usar esto para proporcionar acceso a archivos basado en el tiempo, como por ejemplo: permitir que solo se carguen archivos hasta una fecha determinada, o permitir que solo se lean archivos hasta una hora después de que se cargaron.

// Allow a read if the file was created less than one hour ago
allow read: if request.time < resource.timeCreated + duration.value(1, 'h');

Se proporcionan muchas funciones para escribir reglas utilizando marcas de tiempo y duraciones .

Recurso

La variable resource contiene metadatos de archivos en Cloud Storage, como el nombre del archivo, el tamaño, la hora de creación y los metadatos personalizados.

Propiedades

name

Una cadena que contiene el nombre completo del archivo, incluida la ruta al archivo.

// Allow reads if the resource name is "path/to/object"
allow read: if resource.name == 'path/to/object'

bucket

Una cadena que contiene el depósito de Google Cloud Storage en el que se almacena este archivo.

// Allow reads of all resources in your bucket
allow read: if resource.bucket == '<your-cloud-storage-bucket>'

generation

Un int que contiene la generación del objeto de Google Cloud Storage del archivo. Se utiliza para el control de versiones de objetos.

// Allow reads if the resource matches a known object version
allow read: if resource.generation == <known-generation>

metageneration

Un int que contiene la metageneración del objeto de Google Cloud Storage del archivo. Se utiliza para el control de versiones de objetos.

// Allow reads if the resource matches a known object metadata version
allow read: if resource.metageneration == <known-generation>

size

Un int que contiene el tamaño del archivo en bytes.

// Allow reads if the resource is less than 10 MB
allow read: if resource.size < 10 * 1024 * 1024;

timeCreated

Una marca de tiempo que representa cuándo se creó el archivo.

// Allow reads if the resource was created less than an hour ago
allow read: if resource.timeCreated < request.time + duration.value(60, "m")

updated

Una marca de tiempo que representa cuándo se actualizó el archivo por última vez.

// Allow reads if the resource was updated less than an hour ago
allow read: if resource.updated < request.time + duration.value(60, "m")

md5Hash

Una cadena que contiene el hash MD5 del archivo.

// Allow writes if the hash of the uploaded file is the same as the existing file
allow write: if request.resource.md5Hash == resource.md5Hash;

crc32c

Una cadena que contiene el hash crc32c del archivo.

// Allow writes if the hash of the uploaded file is the same as the existing file
allow write: if request.resource.crc32c == resource.crc32c;

etag

Una cadena que contiene la etiqueta e del archivo.

// Allow writes if the etag matches a known object etag
allow write: if resource.etag == <known-generation>

contentDisposition

Una cadena que contiene la disposición del contenido del archivo.

// Allow reads if the content disposition matches a certain value
allow read: if resource.contentDisposition == 'inlined';

contentEncoding

Una cadena que contiene la codificación del contenido del archivo.

// Allow reads if the content is encoded with gzip
allow read: if resource.contentEncoding == 'gzip';

contentLanguage

Una cadena que contiene el idioma del contenido del archivo.

// Allow reads if the content language is Japanese
allow read: if resource.contentLanguage == 'ja';

contentType

Una cadena que contiene el tipo de contenido del archivo.

// Allow reads if the content type is PNG.
allow read: if resource.contentType == 'image/png';

metadata

Un Map<String, String> que contiene campos de metadatos adicionales proporcionados por el desarrollador.

// Allow reads if a certain metadata field matches a desired value
allow read: if resource.metadata.customProperty == 'customValue';

firestore.get y firestore.existe

Las funciones firestore.get() y firestore.exists() le permiten acceder a documentos en Cloud Firestore para evaluar criterios de autorización complejos.

Las funciones firestore.get() y firestore.exists() esperan rutas de documentos completamente especificadas. Cuando use variables para construir rutas para firestore.get() y firestore.exists() , debe escapar explícitamente de las variables usando la sintaxis $(variable) .

firestore.get

Obtén el contenido de un documento de Cloud Firestore.

service firebase.storage {
  match /b/{bucket}/o {
    match /users/{club}/files/{fileId} {
      allow read: if club in
        firestore.get(/databases/(default)/documents/users/$(request.auth.uid)).data.memberships
    }
  }
}

firestore.existe

Compruebe si existe un documento de Cloud Firestore.

service firebase.storage {
  match /b/{bucket}/o {
    match /users/{userId}/photos/{fileId} {
      allow read: if
        firestore.exists(/databases/(default)/documents/users/$(userId)/friends/$(request.auth.uid))
    }
  }
}

Servicio

El service es la primera declaración en un archivo de reglas de seguridad de almacenamiento en la nube y especifica a qué servicio se aplicarán estas reglas.

Nombre

name

El nombre de las reglas de servicio a las que se aplicarán. El único valor actual es firebase.storage .

// Specify the service name
service firebase.storage {
  match /b/{bucket}/o {
    ...
  }
}

Tipos de datos

El lenguaje de reglas le permite verificar el tipo usando el operador is .

// For example
a is null
a is string

null

El tipo de datos null representa un valor que no existe.

allow read: if request.auth != null;

bool

El tipo bool representa un valor booleano true o false .

allow read: if true;   // always succeeds
allow write: if false; // always fails

Comparación

Los valores booleanos se pueden comparar usando los operadores == != .

Operaciones booleanas

Operación Expresión
AND x && y
OR x || y
NOT !x

Las operaciones provocan un cortocircuito y pueden devolver true , false o un Error .

allow read: if true || false;   // always succeeds, short circuits at true
allow write: if false && true; // always fails, short circuits at false

int y float

Los tipos int y float representan números. Los enteros son: 0 , 1 , -2 , etc., mientras que los flotantes son: 1.0 , -2.0 , 3.33 , etc.

Los enteros son valores de 64 bits con signo y los flotantes son valores compatibles con IEEE 754 de 64 bits. Los valores de tipo int serán obligados a float cuando se utilicen en comparaciones y operaciones aritméticas con un valor float .

Comparación

Los enteros y flotantes se pueden comparar y ordenar usando los operadores == , != , > , < , >= y <= .

Aritmética

Los enteros y flotantes se pueden sumar, restar, multiplicar, dividir, modular y negar:

Operación Expresión
Suma x + y
Sustracción x - y
Multiplicación x * y
División x / y
módulo x % y
Negación -x

Funciones matemáticas

Firebase Security Rules for Cloud Storage también proporciona una serie de funciones auxiliares matemáticas para simplificar expresiones:

Función Descripción
math.ceil(x) Techo del valor numérico
math.floor(x) Piso del valor numérico.
math.round(x) Redondea el valor de entrada al int más cercano
math.abs(x) Valor absoluto de la entrada
math.isInfinite(x) Pruebe si el valor es ±∞ , devuelve un bool
math.isNaN(x) Prueba si el valor no es un número NaN , devuelve un bool

string

Comparación

Las cadenas se pueden comparar y ordenar lexográficamente utilizando los operadores == , != , > , < , >= y <= .

Concatenación

Las cadenas se pueden concatenar usando el operador + .

// Concatenate a file name and extension
'file' + '.txt'

Índice y rango

El operador index , string[] , devuelve una cadena que contiene el carácter en el índice proporcionado en la cadena.

// Allow reads of files that begin with 'a'
match /{fileName} {
  allow read: if fileName[0] == 'a';
}

El operador range , string[i:j] , devuelve una cadena que contiene los caracteres entre los índices especificados, desde i (inclusive) hasta j (exclusivo). Si no se especifican i o j , el valor predeterminado es 0 y el tamaño de la cadena, respectivamente, pero se debe especificar al menos i o j para que el rango sea válido.

// Allow reads of files that begin with 'abcdef'
match /{fileName} {
  allow read: if fileName[0:6] == 'abcdef';
}

Los operadores index y range generarán un error si los índices proporcionados exceden los límites de la cadena.

size

Devuelve el número de caracteres de la cadena.

// Allow files with names less than 10 characters
match /{fileName} {
  allow write: if fileName.size() < 10;
}

matches

Realiza una coincidencia de expresión regular y devuelve true si la cadena coincide con la expresión regular dada. Utiliza la sintaxis de Google RE2 .

// Allow writes to files which end in ".txt"
match /{fileName} {
  allow write: if fileName.matches('.*\\.txt')
}

split

Divide una cadena según una expresión regular proporcionada y devuelve una list de cadenas. Utiliza la sintaxis de Google RE2 .

// Allow files named "file.*" to be uploaded
match /{fileName} {
  allow write: if fileName.split('.*\\..*')[0] == 'file'
}

path

Las rutas son nombres similares a directorios con coincidencia de patrones opcional. La presencia de una barra diagonal / indica el inicio de un segmento de ruta.

path

Convierte un argumento string en una path .

// Allow reads on a specific file path
match /{allFiles=**} {
  allow read: if allFiles == path('/path/to/file');
}

timestamp

Las marcas de tiempo están en UTC, con valores posibles que comienzan en 0001-01-01T00.00.00Z y terminan en 9999-12-31T23.59.59Z.

Comparación

Las marcas de tiempo se pueden comparar y ordenar utilizando los operadores == , != , > , < , >= y <= .

Aritmética

Las marcas de tiempo admiten sumas y restas entre marcas de tiempo y duraciones de la siguiente manera:

Expresión Resultado
timestamp + duration timestamp
duration + timestamp timestamp
timestamp - duration timestamp
timestamp - timestamp duration
duration + duration duration
duration - duration duration

date

Un valor timestamp que contiene únicamente el year , month y day .

// Allow reads on the same day that the resource was created.
allow read: if request.time.date() == resource.timeCreated.date()

year

El valor del año como un int, de 1 a 9999.

// Allow reads on all requests made before 2017
allow read: if request.time.year() < 2017

month

El valor del mes como un int, de 1 a 12.

// Allow reads on all requests made during the month of January
allow read: if request.time.month() == 1;

day

El día actual del mes como un int, del 1 al 31.

// Allow reads on all requests made during the first day of each month
allow read: if request.time.day() == 1;

time

Un valor duration que contiene la hora actual.

// Allow reads on all requests made before 12PM
allow read: if request.time.time() < duration.time(12, 0, 0, 0);

hours

El valor de las horas es un int, de 0 a 23.

// Allow reads on all requests made before 12PM
allow read: if request.time.hours() < 12;

minutes

El valor de los minutos es un int, de 0 a 59.

// Allow reads during even minutes of every hour
allow read: if request.time.minutes() % 2 == 0;

seconds

El valor de los segundos como un int, de 0 a 59.

// Allow reads during the second half of each minute
allow read: if request.time.seconds() > 29;

nanos

Las fracciones de segundo en nanos como un int.

// Allow reads during the first 0.1 seconds of each second
allow read: if request.time.nanos() < 100000000;

dayOfWeek

El día de la semana, de 1 (lunes) a 7 (domingo).

// Allow reads on weekdays (Monday to Friday)
allow read: if request.time.dayOfWeek() < 6;

dayOfYear

El día del año en curso, del 1 al 366.

// Allow reads every fourth day
allow read: if request.time.dayOfYear() % 4 == 0;

toMillis

Devuelve el número actual de milisegundos desde la época de Unix.

// Allow reads if the request is made before a specified time
allow read: if request.time.toMillis() < <milliseconds>;

duration

Los valores de duración se representan como segundos más fracciones de segundo en nanosegundos.

Comparación

Las duraciones se pueden comparar y ordenar utilizando los operadores == , != , > , < , >= y <= .

Aritmética

Las duraciones admiten sumas y restas entre marcas de tiempo y duraciones de la siguiente manera:

Expresión Resultado
timestamp + duration timestamp
duration + timestamp timestamp
timestamp - duration timestamp
timestamp - timestamp duration
duration + duration duration
duration - duration duration

seconds

El número de segundos de la duración actual. Debe estar entre -315.576.000.000 y +315.576.000.000 inclusive.

nanos

El número de fracciones de segundo (en nanosegundos) de la duración actual. Debe estar entre -999.999.999 y +999.999.999 inclusive. Para segundos distintos de cero y nanosegundos distintos de cero, los signos de ambos deben coincidir.

duration.value

Las duraciones se pueden crear usando la función duration.value(int magnitude, string units) , que crea una duración de tiempo a partir de la magnitud y unidad dadas.

// All of these durations represent one hour:
duration.value(1, "h")
duration.value(60, "m")
duration.value(3600, "s")

Las posibles unit son:

Duración unit
Semanas w
Días d
Horas h
Minutos m
Segundos s
Milisegundos ms
Nanosegundos ns

duration.time

Las duraciones se pueden crear usando la función duration.time(int hours, int minutes, int seconds, int nanoseconds) , que crea una duración de tiempo de las horas, minutos, segundos y nanosegundos dados.

// Create a four hour, three minute, two second, one nanosecond duration
duration.time(4, 3, 2, 1)

list

Una lista contiene una matriz ordenada de valores, que pueden ser de tipo: null , bool , int , float , string , path , list , map , timestamp o duration .

Dados x e y de list de tipos e i y j de tipo int

Creación

Para crear una lista, agregue valores entre paréntesis:

// Create a list of strings
['apples', 'grapes', 'bananas', 'cheese', 'goats']

Comparación

Las listas se pueden comparar usando los operadores == != . La igualdad de dos listas requiere que todos los valores sean iguales.

Índice y rango

El operador index , list[] , devuelve el elemento en el índice proporcionado en la lista.

// Allow reads of all files that begin with 'a'
match /{fileName} {
  allow read: if fileName[0] == 'a';
}

El operador range , list[i:j] , devuelve todos los elementos de una lista entre los índices especificados, desde i (inclusive) hasta j (exclusivo). Si no se especifican i o j , el valor predeterminado es 0 y el tamaño de la lista, respectivamente, pero se debe especificar al menos i o j para que el rango sea válido.

// Allow reads of all files that begin with 'abcdef'
match /{fileName} {
  allow read: if fileName[0:6] == 'abcdef';
}

in

Devuelve true si el valor deseado está presente en la lista o false si no está presente.

// Allow read if a filename has the string 'txt' in it
match /{fileName} {
  allow read: if 'txt' in fileName.split('\\.');
}

join

Combina una lista de cadenas en una sola cadena, separada por la cadena dada.

// Allow reads if the joined array is 'file.txt'
allow read: if ['file', 'txt'].join('.') == 'file.txt';

size

El número de elementos de la lista.

// Allow read if there are three items in our list
allow read: if ['foo', 'bar', 'baz'].size() == 3;

hasAll

Devuelve true si todos los valores están presentes en la lista.

// Allow read if one list has all items in the other list
allow read: if ['file', 'txt'].hasAll(['file', 'txt']);

map

Un mapa contiene pares clave/valor, donde las claves son cadenas y los valores pueden ser cualquiera de: null , bool , int , float , string , path , list , map , timestamp o duration .

Creación

Para crear un mapa, agregue pares clave/valor entre llaves:

// Create a map of strings to strings
{
  'mercury': 'mars',
  'rain': 'cloud',
  'cats': 'dogs',
}

Comparación

Los mapas se pueden comparar usando los operadores == != . La igualdad de dos mapas requiere que todas las claves estén presentes en ambos mapas y que todos los valores sean iguales.

Índice

Se accede a los valores en un mapa mediante notación entre corchetes o puntos:

// Access custom metadata properties
allow read: if resource.metadata.property == 'property'
allow write: if resource.metadata['otherProperty'] == 'otherProperty'

Si no hay una clave presente, se devolverá un error .

in

Devuelve true si la clave deseada está presente en el mapa o false si no está presente.

// Allow reads if a property is present in the custom metadata
allow read: if property in resource.metadata;

size

El número de claves en el mapa.

// Allow reads if there's exactly one custom metadata key
allow read: if resource.metadata.size() == 1;

keys

Una lista de todas las claves en el mapa.

// Allow reads if the first metadata key is 'myKey'
allow read: if resource.metadata.keys()[0] == 'myKey';

values

Una lista de todos los valores del mapa, en orden clave.

// Allow reads if the first metadata value is 'myValue'
allow read: if resource.metadata.values()[0] == 'myValue';

Errores

Evaluación de errores

Las reglas de seguridad de Firebase para Cloud Storage continúan la evaluación cuando se encuentran errores. Esto es útil porque condicional && y || las expresiones pueden absorber un error si el condicional provocaría un cortocircuito en false o true respectivamente. Por ejemplo:

Expresión Resultado
error && true error
error && false false
error || true true
error || false error

Los lugares comunes donde se generan errores son: división por cero, acceder a valores en una lista o mapa que no existen y pasar valores del tipo incorrecto a una función.

// Error if resource.size is zero
allow read: if 1000000 / resource.size;

// Error, key doesn't exist
allow read: if resource.metadata.nonExistentKey == 'value';

// Error, no unit 'y' exists
allow read: if request.time < resource.timeCreated + duration.value(1, 'y');