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

As Firebase Security Rules para Cloud Storage são usadas para determinar quem tem acesso de leitura e gravação aos arquivos armazenados no Cloud Storage, além de como os arquivos são estruturados e quais metadados elas contêm. Cloud Storage Security Rules são compostas de regras que considere a request e a resource para permitir ou negar uma ação desejada, como como fazer upload de um arquivo ou recuperar metadados de arquivos. Estes documentos de referência abrangem os tipos de regras, as propriedades de uma request e uma resource, os dados tipos usados por Cloud Storage Security Rules e como os erros ocorrem.

Regra

Um rule é uma expressão que é avaliada para determinar se um request é para realizar uma ação desejada.

Tipos

Allow

As regras allow consistem em um método, como read ou write, bem como uma condição opcional. Quando uma regra é executada, a condição é avaliada Se a condição for avaliada como true, o método desejado será permitido. caso contrário, o método é negado. Uma regra allow sem condição sempre permite a 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 aceito.

Métodos de solicitação

Ler

O método read abrange todas as solicitações em que são lidos dados ou metadados de arquivos. 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>;

Gravação

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

// Always allow writes
allow write;

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

Correspondência

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

É possível usar match em um caminho totalmente nomeado ou inserir caracteres curinga para corresponder a todos caminhos que se encaixam em um determinado padrão.

Segmentos de caminho

single_segment

É possível usar segmentos de caminho único para criar uma regra que corresponda a um arquivo armazenado em Cloud Storage.

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

Vários 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 quiser aplicar uma regra a vários arquivos no mesmo caminho, use um segmento de caminho curinga para corresponder a todos os arquivos em um determinado caminho. Uma variável curinga é declarado em um caminho ao colocar uma variável entre chaves: {variable}. Essa variável pode ser acessada na instrução de correspondência como um 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>;
}

Vários segmentos de caminho e caminhos aninhados também podem ter caracteres curinga:

// 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ê quiser corresponder qualquer número de segmentos em um caminho ou abaixo dele, use um caractere curinga de vários segmentos, que corresponderá a todas as solicitações para e abaixo do o local. Isso pode ser útil para fornecer ao usuário seu próprio formato espaço de armazenamento ou criar regras que correspondam a muitos segmentos de caminho diferentes (como como criar um conjunto de arquivos publicamente legível ou exigir autenticação para todas as gravações).

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

Solicitação

A variável request é fornecida dentro de uma condição para representar o que está sendo feita nesse caminho. A variável request tem vários que podem ser usadas para decidir se a solicitação de entrada será permitida.

Propriedades

auth

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

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

Campo Descrição
email O endereço de e-mail associado à conta, se essa informação existir.
email_verified true se o usuário tiver verificado que tem acesso ao endereço email. Alguns provedores verificam automaticamente esses endereços de e-mail.
phone_number O número de telefone associado à conta, se essa informação existir.
name O nome de exibição do usuário, se ele tiver sido definido.
sub O UID do Firebase do usuário. Ele é exclusivo dentro de um projeto.
firebase.identities O dicionário de todas as identidades associadas à conta desse 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 de 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 entrada usado para receber esse token. Pode ser uma das seguintes strings: custom, password, phone, anonymous, google.com, facebook.com, github.com ou twitter.com.
firebase.tenant O ID do locatário associado à conta, se houver. Por exemplo, tenant2-m6tyz.

Se você estiver usando a autenticação personalizada, request.auth.token também conterá qualquer reivindicações especificadas pelo desenvolvedor.

Quando um usuário não autenticado realiza 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 que uma request está sendo executada. contra.

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

resource

A variável resource contém os metadados de um arquivo que está sendo enviado ou o metadados atualizados de um arquivo existente. Isso está relacionado à A variável resource, que contém os metadados do arquivo atuais em o caminho solicitado, em vez dos 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 de resource:

Propriedade
name
bucket
metadata
size
contentType

time

A variável time contém um carimbo de data/hora que representa o horário atual do servidor em que uma solicitação está sendo avaliada. Use isso para fornecer acesso com base no tempo a arquivos, como: permitir apenas o upload de arquivos até uma determinada data; ou permitir que os arquivos sejam lidos até uma hora após o upload.

// 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 gravar regras usando carimbos de data/hora e durations.

Recurso

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

Propriedades

name

String com o nome completo do arquivo, incluindo o caminho para ele.

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

bucket

Uma string contendo o Google Cloud Storage no bucket em que esse arquivo está armazenado.

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

generation

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

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

metageneration

Um inteiro que contém o arquivo do Google Cloud Storage metageração de objeto do arquivo. Usado para controle de versão de objetos.

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

size

Um inteiro 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

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 .

// 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 crc32c hash do .

// 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 que contém a etag do .

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

contentDisposition

String com a disposição de conteúdo do arquivo.

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

contentEncoding

String com a codificação de conteúdo do arquivo.

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

contentLanguage

String com o idioma do conteúdo do arquivo.

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

contentType

String com 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 metadados adicionais fornecidos pelo desenvolvedor campos.

// 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 em Cloud Firestore para avaliar critérios de autorização complexos.

As funções firestore.get() e firestore.exists() esperam caminhos de documento totalmente especificados. Ao usar variáveis para criar caminhos para firestore.get() e firestore.exists(), você precisa fazer o escape explícito variáveis usando a sintaxe $(variable).

firestore.get

Recebe o conteúdo de um documento 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.exists

Verifique se existe um documento 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 Cloud Storage Security Rules. especifica a qual serviço essas regras serão aplicadas.

Nome

name

O nome das regras de serviço a que as 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

O idioma Rules permite verificar o tipo usando o operador is.

// For example
a is null
a is string

null

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

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 causam um curto-circuito e podem retornar true, false ou uma Erro.

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 os pontos flutuantes são: 1.0, -2.0, 3.33 etc.

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

Comparação

Ints e pontos flutuantes podem ser comparados e ordenados usando ==, !=, >, <, operadores >= e <=.

Aritmética

Ints e pontos flutuantes podem ser adicionados, subtraídos, multiplicados, divididos, modulados e negado:

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

O Firebase Security Rules para Cloud Storage também oferece vários assistentes de matemática para simplificar expressões:

Função Descrição
math.ceil(x) Limite do valor numérico
math.floor(x) Valor mínimo do valor numérico
math.round(x) Arredondar o valor de entrada para o int mais próximo
math.abs(x) Valor absoluto da entrada
math.isInfinite(x) Teste se o valor é ±∞ e retorna um bool.
math.isNaN(x) Teste se o valor não é um número NaN, retorna um bool

string

Comparação

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

Concatenação

Strings podem ser concatenadas usando o operador +.

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

Índice e intervalo

O operador 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 range, string[i:j], retorna uma string que contém o caracteres entre os índices especificados, de i (inclusive) até j (exclusivo). Se i ou j não forem especificados, o padrão será 0 e o tamanho do a string, respectivamente, mas pelo menos i ou j precisam ser especificados 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 index e range resultarão em erro se os índices fornecidos excedem os limites de 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 ao usando uma determinada expressão regular. Usos Sintaxe do Google RE2.

// 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 um list. de strings. Usa a sintaxe do Google RE2.

// 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 A presença de uma barra / indica o início de um segmento de caminho.

path

Converte um argumento string em um path.

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

timestamp

Os carimbos de data/hora estão em UTC, com valores possíveis começando em 0001-01-01T00.00.00Z e termina em 9999-12-31T23.59.59Z.

Comparação

Os carimbos de data/hora podem ser comparados e ordenados usando ==, !=, >, <, >= e Operadores <=.

Aritmética

Os carimbos de data/hora são compatíveis com adição e subtração entre carimbos de data/hora e durações, como 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 timestamp 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 em formato inteiro, de 1 a 9.999.

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

month

O valor do mês como um inteiro, 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 inteiro, 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 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 inteiro, de 0 a 23.

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

minutes

O valor dos minutos como um inteiro, 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 inteiro, de 0 a 59.

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

nanos

A fração de segundos, em nanos, como um inteiro.

// 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 ==, !=, >, <, >= e Operadores <=.

Aritmética

As durações são compatíveis com adição e subtração entre carimbos de data/hora e durações, como 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. Precisa ser entre -315.576.000.000 e +315.576.000.000, inclusive.

nanos

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

duration.value

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

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

Os units 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 o método função duration.time(int hours, int minutes, int seconds, int nanoseconds), que cria uma duração de horas, minutos, segundos e nanossegundos.

// 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 pode 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 == !=. Igualdade de duas listas exige que todos os valores sejam iguais.

Índice e intervalo

O operador 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 range, list[i:j], retorna todos os itens em uma lista entre as índices especificados, de i (inclusivo) até j (exclusivo). Se i ou j forem não especificados, o padrão será 0 e o tamanho da lista, respectivamente, mas pelo menos i ou j precisam ser especificados 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 pretendido 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 por uma determinada.

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

size

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 qualquer de: null, bool, int, float, string, path, list, map, timestamp ou duration.

Criação

Para criar um mapa, adicione pares de 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 == !=. Igualdade de dois mapas requer que todas as chaves estejam presentes em ambos os mapas e que todos os valores sejam iguais.

Índice

Para acessar os valores em um mapa, use a notação de colchete ou ponto:

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

Se não houver uma chave, 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 erros

Firebase Security Rules para Cloud Storage continua a avaliação quando são encontrados erros. Isso é útil porque as expressões condicionais && e || podem absorver um erro se a condicional entrar em curto-circuito para false ou true respectivamente. Por exemplo:

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

Locais comuns em que são gerados erros são: divisão por zero, acesso a valores em uma lista ou mapa que não existe e passar valores do tipo incorreto a 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');