Referência de regras de segurança do Firebase para Cloud Storage

As regras de segurança do Firebase para armazenamento em nuvem são usadas para determinar quem tem acesso de leitura e gravação aos arquivos armazenados no armazenamento em nuvem, bem como como os arquivos são estruturados e quais metadados eles contêm. As regras de segurança do Cloud Storage são compostas por regras que consideram a request e o resource para permitir ou negar uma ação desejada, como carregar um arquivo ou recuperar metadados de arquivo. Esses documentos de referência abrangem os tipos de regras, as propriedades de uma request e um resource , os tipos de dados usados ​​pelas regras de segurança do Cloud Storage e como os erros ocorrem.

Regra

Uma rule é uma expressão avaliada para determinar se uma request tem permissão para executar uma ação desejada.

tipos

Permitir

allow regras consistem em um método, como read ou write , bem como uma condição opcional. Quando uma regra é executada, a condição é avaliada e, se a condição for avaliada como true , o método desejado é permitido; caso contrário, o método é negado. Uma regra de allow sem condição sempre permite o método desejado.

// Always allow method
allow <method>;

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

Atualmente, allow é o único tipo de regra com suporte.

Métodos de Solicitação

Ler

O método read abrange todas as solicitações em que dados de arquivo ou metadados são lidos, incluindo downloads de arquivos e leituras de metadados de arquivos.

// Always allow reads
allow read;

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

Escreva

O método write abrange todas as solicitações em que dados de arquivo ou metadados são gravados, incluindo uploads de arquivos, exclusões de arquivos e atualizações de metadados de arquivos.

// Always allow writes
allow write;

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

Combine

As regras são executadas quando uma request do usuário (como um upload ou download de arquivo) corresponde a um caminho de arquivo coberto por uma regra. Uma match consiste em um caminho e um corpo, que deve conter pelo menos uma regra de allow . Se nenhum caminho for encontrado, a solicitação será rejeitada.

Você pode match a um caminho totalmente nomeado ou inserir curingas para corresponder a todos os caminhos que se ajustam a um determinado padrão.

Segmentos de caminho

single_segment

Você pode usar segmentos de caminho único para criar uma regra que corresponda a um arquivo armazenado no Cloud Storage.

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

Múltiplos segmentos de caminho e caminhos aninhados também são permitidos:

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

{single_segment_wildcard}

Se você deseja aplicar uma regra a vários arquivos no mesmo caminho, pode usar um segmento de caminho curinga para corresponder a todos os arquivos em um determinado caminho. Uma variável curinga é declarada em um caminho envolvendo uma variável entre chaves: {variable} . Essa variável é acessível dentro da instrução match como uma 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>;
}

Múltiplos segmentos de caminho e caminhos aninhados também podem ter curingas:

// 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=**}

Se você deseja corresponder a qualquer número de segmentos de caminho em ou abaixo de um caminho, pode usar um curinga de vários segmentos, que corresponderá a todas as solicitações para e abaixo do local. Isso pode ser útil para fornecer ao usuário seu próprio espaço de armazenamento de formato livre ou criar regras que correspondam a muitos segmentos de caminho diferentes (como criar um conjunto de arquivos legíveis publicamente ou exigir autenticação para todas as gravações).

Um caminho curinga de vários segmentos é declarado de forma semelhante a um curinga de segmento único, com a adição de =** no final da variável: {variable=**} . Uma variável curinga de vários segmentos está disponível na instrução de correspondência como um objeto de 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>;
}

Solicitar

A variável de request é fornecida dentro de uma condição para representar a solicitação sendo feita naquele caminho. A variável de request possui várias propriedades que podem ser usadas para decidir se deve permitir a solicitação de entrada.

Propriedades

auth

Quando um usuário autenticado executa uma solicitação no Cloud Storage, a variável auth é preenchida com o uid do usuário ( request.auth.uid ), bem como as declarações do Firebase Authentication JWT ( request.auth.token ).

request.auth.token contém algumas ou todas as seguintes chaves:

Campo Descrição
email O endereço de e-mail associado à conta, se presente.
email_verified true se o usuário tiver verificado que tem acesso ao endereço de email . Alguns provedores verificam automaticamente os endereços de e-mail que possuem.
phone_number O número de telefone associado à conta, se presente.
name O nome de exibição do usuário, se definido.
sub O UID do Firebase do usuário. Isso é único dentro de um projeto.
firebase.identities Dicionário de todas as identidades associadas à conta deste usuário. As chaves do dicionário podem ser qualquer uma das seguintes: email , phone , google.com , facebook.com , github.com , twitter.com . Os valores do dicionário são matrizes de identificadores exclusivos para cada provedor de identidade associado à conta. Por exemplo, auth.token.firebase.identities["google.com"][0] contém o primeiro ID de usuário do Google associado à conta.
firebase.sign_in_provider O provedor de login usado para obter esse token. Pode ser uma das seguintes strings: custom , password , phone , anonymous , google.com , facebook.com , github.com , twitter.com .
firebase.tenant O tenantId associado à conta, se presente. por exemplo tenant2-m6tyz

Se estiver usando autenticação personalizada, request.auth.token também contém quaisquer declarações personalizadas especificadas pelo desenvolvedor.

Quando um usuário não autenticado executa uma solicitação, request.auth é null .

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

path

A variável path contém o caminho no qual uma request está sendo executada.

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

resource

A variável de resource contém os metadados de um arquivo que está sendo carregado ou os metadados atualizados de um arquivo existente. Isso está relacionado à variável de resource , que contém os metadados do arquivo atual no caminho solicitado, em oposição aos novos metadados.

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

request.resource contém as seguintes propriedades do resource :

Propriedade
name
bucket
metadata
size
contentType

time

A variável time contém um carimbo de data/hora que representa a hora atual do servidor em que uma solicitação está sendo avaliada. Você pode usar isso para fornecer acesso baseado em tempo aos arquivos, como: permitir que os arquivos sejam carregados apenas até uma determinada data ou permitir que os arquivos sejam lidos até uma hora depois de terem sido carregados.

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

Muitas funções são fornecidas para escrever regras usando timestamps e durações .

Recurso

A variável de resource contém metadados de arquivo para arquivos no Cloud Storage, como o nome do arquivo, tamanho, hora de criação e metadados personalizados.

Propriedades

name

Uma string contendo o nome completo do arquivo, incluindo o caminho para o arquivo.

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

bucket

Uma string contendo o bucket do Google Cloud Storage em que este arquivo está armazenado.

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

generation

Um int que contém a geração do objeto Google Cloud Storage do arquivo. Usado para controle de versão de objeto.

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

metageneration

Um int contendo a metageração do objeto Google Cloud Storage do arquivo. Usado para controle de versão de objeto.

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

size

Um int contendo o tamanho do arquivo em bytes.

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

timeCreated

Um carimbo de data/hora que representa quando o arquivo foi criado.

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

updated

Um carimbo de data/hora que representa quando o arquivo foi atualizado pela ú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

Uma string contendo o hash MD5 do arquivo.

// 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

Uma string contendo o hash crc32c do arquivo.

// 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

Uma string contendo o etag do arquivo.

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

contentDisposition

Uma string contendo a disposição do conteúdo do arquivo.

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

contentEncoding

Uma string contendo a codificação de conteúdo do arquivo.

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

contentLanguage

Uma string contendo o idioma do conteúdo do arquivo.

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

contentType

Uma string contendo o tipo de conteúdo do arquivo.

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

metadata

Um Map<String, String> contendo campos de metadados adicionais fornecidos pelo desenvolvedor.

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

firestore.get e firestore.exists

As funções firestore.get() e firestore.exists() permitem que você acesse documentos no Cloud Firestore para avaliar critérios de autorização complexos.

As funções firestore.get() e firestore.exists() esperam caminhos de documentos totalmente especificados. Ao usar variáveis ​​para construir caminhos para firestore.get() e firestore.exists() , você precisa escapar explicitamente das variáveis ​​usando a sintaxe $(variable) .

firestore.get

Obtenha o conteúdo de um documento do 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

Verifique se existe um documento do 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))
    }
  }
}

Serviço

O service é a primeira declaração em um arquivo de regras de segurança do Cloud Storage e especifica a qual serviço essas regras serão aplicadas.

Nome

name

O nome das regras de serviço serão aplicadas. O único valor atual é firebase.storage .

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

Tipos de dados

A linguagem Rules permite que você verifique o tipo usando o operador is .

// For example
a is null
a is string

null

O tipo de dados null representa um valor não existente.

allow read: if request.auth != null;

bool

O tipo bool representa um valor booleano true ou false .

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

Comparação

Os valores booleanos podem ser comparados usando os operadores == != .

Operações Booleanas

Operação Expressão
AND x && y
OR x || y
NOT !x

As operações estão em curto-circuito e podem retornar true , false ou um Error .

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

int e float

Os tipos int e float representam números. Ints são: 0 , 1 , -2 , etc. , enquanto floats são: 1.0 , -2.0 , 3.33 , etc.

Ints são valores assinados de 64 bits e floats são valores compatíveis com IEEE 754 de 64 bits. Valores do tipo int serão forçados a float quando usados ​​em comparações e operações aritméticas com um valor float .

Comparação

Ints e floats podem ser comparados e ordenados usando os operadores == , != , > , < , >= e <= .

Aritmética

Ints e floats podem ser adicionados, subtraídos, multiplicados, divididos, modulados e negados:

Operação Expressão
Adição x + y
Subtração x - y
Multiplicação x * y
Divisão x / y
Módulo x % y
Negação -x

funções matemáticas

As regras de segurança do Firebase para armazenamento em nuvem também fornecem várias funções auxiliares matemáticas para simplificar as expressões:

Função Descrição
math.ceil(x) Teto do valor numérico
math.floor(x) Piso do valor numérico
math.round(x) Arredonde o valor de entrada para o int mais próximo
math.abs(x) Valor absoluto da entrada
math.isInfinite(x) Testa se o valor é ±∞ , retorna um bool
math.isNaN(x) Testa se o valor não é um número NaN , retorna um bool

string

Comparação

Strings podem ser comparadas lexograficamente e ordenadas usando os operadores == , != , > , < , >= e <= .

Concatenação

Strings podem ser concatenadas usando o operador + .

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

Índice e intervalo

O operador de index , string[] , retorna uma string que contém o caractere no índice fornecido na string.

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

O operador de range , string[i:j] , retorna uma string que contém os caracteres entre os índices especificados, de i (inclusivo) até j (exclusivo). Se i ou j não forem especificados, o padrão será 0 e o tamanho da string, respectivamente, mas pelo menos i ou j deve ser especificado para que o intervalo seja válido.

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

Os operadores de index e range produzirão um erro se os índices fornecidos excederem os limites da string.

size

Retorna o número de caracteres na string.

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

matches

Executa uma correspondência de expressão regular, retorna true se a string corresponder à expressão regular fornecida. Usa a sintaxe RE2 do Google .

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

split

Divide uma string de acordo com uma expressão regular fornecida e retorna uma list de strings. Usa a sintaxe RE2 do Google .

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

path

Os caminhos são nomes semelhantes a diretórios com correspondência de padrão opcional. A presença de uma barra / denota o início de um segmento de caminho.

path

Converte um argumento de string em um path .

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

timestamp

Os timestamps estão em UTC, com valores possíveis começando em 0001-01-01T00.00.00Z e terminando em 9999-12-31T23.59.59Z.

Comparação

Os timestamps podem ser comparados e ordenados usando os operadores == , != , > , < , >= e <= .

Aritmética

Timestamps suportam adição e subtração entre timestamps e durações da seguinte forma:

Expressão Resultado
timestamp + duration timestamp
duration + timestamp timestamp
timestamp - duration timestamp
timestamp - timestamp duration
duration + duration duration
duration - duration duration

date

Um valor de timestamp de data/hora contendo apenas year , month e day .

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

year

O valor do ano como um int, de 1 a 9999.

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

month

O valor do mês como um int, de 1 a 12.

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

day

O dia atual do mês como um int, de 1 a 31.

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

time

Um valor de duration contendo a hora atual.

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

hours

O valor das horas como um int, de 0 a 23.

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

minutes

O valor de minutos como um int, de 0 a 59.

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

seconds

O valor dos segundos como um int, de 0 a 59.

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

nanos

Os segundos fracionários em nanos como um int.

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

dayOfWeek

O dia da semana, de 1 (segunda-feira) a 7 (domingo).

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

dayOfYear

O dia do ano atual, de 1 a 366.

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

toMillis

Retorna o número atual de milissegundos desde a época do Unix.

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

duration

Os valores de duração são representados como segundos mais segundos fracionários em nanossegundos.

Comparação

As durações podem ser comparadas e ordenadas usando os operadores == , != , > , < , >= e <= .

Aritmética

As durações suportam adição e subtração entre timestamps e durações da seguinte forma:

Expressão Resultado
timestamp + duration timestamp
duration + timestamp timestamp
timestamp - duration timestamp
timestamp - timestamp duration
duration + duration duration
duration - duration duration

seconds

O número de segundos na duração atual. Deve estar entre -315.576.000.000 e +315.576.000.000 inclusive.

nanos

O número de segundos fracionários (em nanossegundos) da duração atual. Deve estar entre -999.999.999 e +999.999.999 inclusive. Para segundos diferentes de zero e nanonsegundos diferentes de zero, os sinais de ambos devem estar de acordo.

duration.value

As durações podem ser criadas usando a função duration.value(int magnitude, string units) , que cria uma duração de tempo a partir da magnitude e unidade fornecidas.

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

As unit possíveis são:

Duração unit
Semanas w
Dias d
Horas h
Minutos m
Segundos s
Milissegundos ms
Nanossegundos ns

duration.time

As durações podem ser criadas usando a função duration.time(int hours, int minutes, int seconds, int nanoseconds) , que cria uma duração de horas, minutos, segundos e nanossegundos fornecidos.

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

list

Uma lista contém uma matriz ordenada de valores, que podem ser do tipo: null , bool , int , float , string , path , list , map , timestamp ou duration .

Dados x e y do tipo list e i e j do tipo int

Criação

Para criar uma lista, adicione valores entre colchetes:

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

Comparação

As listas podem ser comparadas usando os operadores == != . A igualdade de duas listas exige que todos os valores sejam iguais.

Índice e intervalo

O operador de index , list[] , retorna o item no índice fornecido na lista.

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

O operador de range , list[i:j] , retorna todos os itens em uma lista entre os índices especificados, de i (inclusivo) até j (exclusivo). Se i ou j não forem especificados, o padrão será 0 e o tamanho da lista, respectivamente, mas pelo menos i ou j deve ser especificado para que o intervalo seja válido.

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

in

Retorna true se o valor desejado estiver presente na lista ou false se não estiver presente.

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

join

Combina uma lista de strings em uma única string, separada pela string fornecida.

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

size

O número de itens na lista.

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

hasAll

Retorna true se todos os valores estiverem presentes na lista.

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

map

Um mapa contém pares de chave/valor, em que as chaves são strings e os valores podem ser: null , bool , int , float , string , path , list , map , timestamp ou duration .

Criação

Para criar um mapa, adicione pares chave/valor entre chaves:

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

Comparação

Os mapas podem ser comparados usando os operadores == != . A igualdade de dois mapas requer que todas as chaves estejam presentes em ambos os mapas e todos os valores sejam iguais.

Índice

Os valores em um mapa são acessados ​​usando a notação de colchetes ou pontos:

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

Se uma chave não estiver presente, um error será retornado.

in

Retorna true se a chave desejada estiver presente no mapa ou false se não estiver presente.

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

size

O número de chaves no mapa.

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

keys

Uma lista de todas as chaves no mapa.

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

values

Uma lista de todos os valores no mapa, em ordem de chave.

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

Erros

Avaliação de erro

As regras de segurança do Firebase para armazenamento em nuvem continuam a avaliação quando são encontrados erros. Isso é útil porque condicional && e || as expressões podem absorver um erro se a condicional sofrer um curto-circuito para false ou true , respectivamente. Por exemplo:

Expressão Resultado
error && true error
error && false false
error || true true
error || false error

Os lugares comuns onde os erros são gerados são: divisão por zero, acessar valores em uma lista ou mapa que não existem e passar valores do tipo incorreto para uma função.

// 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');