As regras de segurança do Firebase para Cloud Storage são usadas para determinar quem tem acesso de leitura e gravação aos arquivos armazenados no Cloud Storage, 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 resource
para permitir ou negar uma ação desejada, como fazer upload de um arquivo ou recuperar metadados de arquivo. Esses documentos de referência abrangem os tipos de regras, as propriedades de uma request
e de 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
As regras allow
consistem em um método, como read
ou write
, bem como em 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 será negado. Uma regra 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 compatível.
Métodos de solicitação
Ler
O método read
cobre todas as solicitações em que dados ou metadados de arquivo 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>;
Escrever
O método write
cobre todas as solicitações em que dados ou metadados de arquivo 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>;
Corresponder
As regras são executadas quando uma request
do usuário (como 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 allow
. Se nenhum caminho for correspondido, a solicitação será rejeitada.
Você pode match
a um caminho totalmente nomeado ou inserir caracteres curinga para corresponder a todos os caminhos que se enquadram em 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>; }
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, você poderá usar um segmento de caminho curinga para corresponder todos os arquivos em um determinado caminho. Uma variável curinga é declarada em um caminho envolvendo uma variável entre chaves: {variable}
. Esta variável pode ser acessada na 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>; }
Vários 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 quiser corresponder qualquer número de segmentos de caminho em ou abaixo de um caminho, você poderá 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 multissegmento está disponível na instrução match 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>; }
Solicitar
A variável request
é fornecida em uma condição para representar a solicitação feita naquele caminho. A variável request
possui diversas propriedades que podem ser usadas para decidir se a solicitação recebida será permitida.
Propriedades
auth
Quando um usuário autenticado realiza uma solicitação no Cloud Storage, a variável auth
é preenchida com o uid
do usuário ( request.auth.uid
), bem como com as declarações do JWT do Firebase Authentication ( 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 email . Alguns provedores verificam automaticamente os endereços de e-mail de sua propriedade. |
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 resource
contém os metadados de um arquivo que está sendo carregado ou os metadados atualizados de um arquivo existente. Isto está relacionado à variável 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 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. Você pode usar isso para fornecer acesso aos arquivos com base no tempo, como: permitir que os arquivos sejam carregados apenas até uma determinada data ou permitir que os arquivos sejam lidos apenas até uma hora após 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 carimbos de data e hora e durações .
Recurso
A variável resource
contém metadados de arquivos no Cloud Storage, como nome do arquivo, tamanho, horário 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 que contém o intervalo 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 do arquivo no Google Cloud Storage. Usado para versionamento de objetos.
// Allow reads if the resource matches a known object version allow read: if resource.generation == <known-generation>
metageneration
Um int que contém a metageração de objetos do Google Cloud Storage do arquivo. Usado para versionamento de objetos.
// 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 do 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 adicionais de metadados 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 acessar 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á aplicado. O único valor atual é firebase.storage
.
// Specify the service name service firebase.storage { match /b/{bucket}/o { ... } }
Tipos de dados
A linguagem de regras 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 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 entram 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 Cloud Storage também fornecem diversas funções auxiliares matemáticas para simplificar 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) | Teste se o valor é ±∞ , retorna um bool |
math.isNaN(x) | Teste se o valor não é um número NaN , retorna um bool |
string
Comparação
As strings podem ser comparadas e ordenadas lexograficamente 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 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 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
deverão 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
produzirão um erro se os índices fornecidos excederem os limites da string.
size
Retorna o número de caracteres da 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 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 uma list
de strings. Usa a sintaxe Google RE2 .
// Allow files named "file.*" to be uploaded match /{fileName} { allow write: if fileName.split('.*\\..*')[0] == 'file' }
path
Caminhos são nomes semelhantes a diretórios com correspondência de padrões opcional. 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 e hora 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 carimbos de data e hora podem ser comparados e ordenados usando os operadores ==
, !=
, >
, <
, >=
e <=
.
Aritmética
Os carimbos de data/hora suportam adição e subtração entre carimbos de data/hora 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 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 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 duration
que contém 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 dos 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 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 carimbos de data/hora 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 nanossegundos 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 de uma determinada magnitude e unidade.
// All of these durations represent one hour: duration.value(1, "h") duration.value(60, "m") duration.value(3600, "s")
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 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 os índices especificados, de i
(inclusivo) até j
(exclusivo). Se i
ou j
não forem especificados, o padrão é 0 e o tamanho da lista, respectivamente, mas pelo menos i
ou j
devem 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 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 chave/valor, onde 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 que todos os valores sejam iguais.
Índice
Os valores em um mapa são acessados usando 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 erros
As regras de segurança do Firebase para Cloud Storage continuam a avaliação quando erros são encontrados. Isso é útil porque condicional &&
e ||
expressões 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 onde erros são gerados são: divisão por zero, acesso a valores em uma lista ou mapa que não existem e passagem de 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');