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