Este guia foi desenvolvido com base no guia Aprenda a sintaxe principal da linguagem de Firebase Security Rules para mostrar como adicionar condições a Firebase Security Rules para Cloud Storage.
O elemento básico principal de Cloud Storage Security Rules é a condição. Uma condição é uma expressão booleana que determina se uma operação específica deve ser permitida ou negada. Para regras básicas, o uso de literais true
e false
como condições funciona muito bem. Mas a linguagem de Firebase Security Rules para Cloud Storage oferece maneiras de criar condições mais complexas que podem:
- Verificar a autenticação do usuário
- Validar dados recebidos
Autenticação
As Firebase Security Rules para Cloud Storage integram-se ao Firebase Authentication para fornecer autenticação avançada com base no usuário para o Cloud Storage. Isso permite o controle de acesso granular com base nas declarações de um token do Firebase Authentication.
Quando um usuário autenticado faz uma solicitação no Cloud Storage, a variável request.auth
é preenchida com o uid
do usuário (request.auth.uid
), bem como as declarações do JWT Firebase Authentication (request.auth.token
).
Além disso, ao usar a autenticação personalizada, outras declarações são exibidas no campo request.auth.token
.
Quando um usuário não autenticado realiza uma solicitação, a variável request.auth
é null
.
Com esses dados, há várias maneiras comuns de usar a autenticação para proteger os arquivos:
- Público: ignora
request.auth
- Particular autenticado: verifica se
request.auth
não énull
- Particular por usuário: verifica se
request.auth.uid
é igual a um caminhouid
- Particular por grupo: verifica as declarações do token personalizado para confirmar se elas correspondem a uma declaração escolhida ou lê os metadados do arquivo para ver se existe um campo de metadados
Público
Qualquer regra que não considere o contexto request.auth
pode ser considerada uma regra public
, pois não considera o contexto de autenticação do usuário.
Essas regras podem ser úteis para expor dados públicos, como recursos de um jogo, arquivos de som ou outros conteúdos estáticos.
// Anyone to read a public image if the file is less than 100kB // Anyone can upload a public file ending in '.txt' match /public/{imageId} { allow read: if resource.size < 100 * 1024; allow write: if imageId.matches(".*\\.txt"); }
Particular autenticado
Em determinados casos, os dados devem ser visíveis somente para os usuários autenticados do seu aplicativo. Como a variável request.auth
é null
para todos os usuários não autenticados, basta verificar se a variável request.auth
existe para exigir autenticação:
// Require authentication on all internal image reads match /internal/{imageId} { allow read: if request.auth != null; }
Particular por usuário
De longe, o caso de uso mais comum para request.auth
será conceder permissões granulares aos arquivos para cada usuário, desde o upload de imagens de perfil até a leitura de documentos particulares.
Como os arquivos no Cloud Storage têm um "caminho" completo para o arquivo, para permitir que um usuário controle um arquivo, basta uma informação exclusiva que identifique o usuário no prefixo do nome de arquivo (como o uid
do usuário). Essa informação pode ser verificada quando a regra é avaliada:
// Only a user can upload their profile picture, but anyone can view it match /users/{userId}/profilePicture.png { allow read; allow write: if request.auth.uid == userId; }
Particular por grupo
Outro caso de uso igualmente comum é conceder permissões de acesso a um objeto para um grupo. Por exemplo, permitir que vários membros da equipe colaborem em um documento compartilhado. Há várias abordagens para fazer isso, como:
- produzir um token personalizado do Firebase Authentication que contenha informações adicionais sobre um membro do grupo (por exemplo, um ID do grupo);
- incluir informações do grupo (como um ID do grupo ou uma lista de
uid
s autorizados) nos metadados do arquivo.
Depois que esses dados são armazenados no token ou nos metadados do arquivo, eles podem ser referenciados dentro de uma regra:
// Allow reads if the group ID in your token matches the file metadata's `owner` property // Allow writes if the group ID is in the user's custom token match /files/{groupId}/{fileName} { allow read: if resource.metadata.owner == request.auth.token.groupId; allow write: if request.auth.token.groupId == groupId; }
Avaliação de solicitação
Uploads, downloads, alterações em metadados e exclusões são avaliados usando a request
enviada ao Cloud Storage. Além do ID exclusivo do usuário e do payload do Firebase Authentication no objeto request.auth
, conforme descrito acima, a variável request
conterá o caminho do arquivo em que a solicitação é feita, o momento em que a solicitação é recebida e o novo valor resource
se a solicitação for uma gravação.
O objeto request
também contém o ID exclusivo do usuário e o payload do Firebase Authentication no objeto request.auth
, que será explicado em mais detalhes na seção Segurança baseada no usuário da documentação.
Veja uma lista completa de propriedades no objeto request
:
Propriedade | Tipo | Descrição |
---|---|---|
auth |
map<string, string> | Quando um usuário está conectado, fornece uid , o ID exclusivo do usuário, e token , um mapa de declarações JWT do Firebase Authentication. Caso contrário, será null . |
params |
map<string, string> | Mapa contendo os parâmetros de consulta da solicitação. |
path |
path | Um path que representa o caminho em que a solicitação está sendo
realizada. |
resource |
map<string, string> | O novo valor do recurso, presente apenas nas solicitações write .
|
time |
timestamp | Um carimbo de data/hora que representa o horário do servidor em que a solicitação é avaliada. |
Avaliação de recurso
Durante a avaliação de regras, você também pode avaliar os metadados do arquivo do qual está fazendo upload, download, modificando ou excluindo. Crie regras complexas e eficazes, como permitir o upload somente de arquivos com um conteúdo específico ou apenas a exclusão de arquivos maiores com um tamanho determinado.
As Firebase Security Rules para Cloud Storage fornecem metadados de arquivo no resource
, que contém pares de chave-valor dos metadados exibidos em um objeto Cloud Storage. Essas propriedades podem ser inspecionadas em solicitações read
ou write
para garantir a integridade de dados.
Em solicitações write
(como uploads, atualizações de metadados e exclusões), além do objeto resource
, que contém metadados do arquivo que existe atualmente no caminho da solicitação, você também pode usar o objeto request.resource
, que contém um subconjunto dos metadados de arquivos a serem gravados se a gravação for permitida. Use esses dois valores para garantir a integridade dos dados
ou para aplicar restrições no aplicativo, como de tipo ou tamanho.
Veja uma lista completa de propriedades no objeto resource
:
Propriedade | Tipo | Descrição |
---|---|---|
name |
string | Nome completo do objeto. |
bucket |
string | Nome do bucket do objeto. |
generation |
int | A geração de objetos do Google Cloud Storage desse objeto. |
metageneration |
int | A metageração de objetos do Google Cloud Storage desse objeto. |
size |
int | Tamanho do objeto em bytes. |
timeCreated |
timestamp | Um carimbo de data que indica o horário em que um objeto foi criado. |
updated |
timestamp | Carimbo de data/hora que indica o horário em que um objeto foi atualizado pela última vez. |
md5Hash |
string | Hash MD5 do objeto. |
crc32c |
string | Hash crc32c do objeto. |
etag |
string | Etag associada ao objeto. |
contentDisposition |
string | Disposição do conteúdo associada ao objeto. |
contentEncoding |
string | Codificação do conteúdo associada ao objeto. |
contentLanguage |
string | Idioma do conteúdo associado ao objeto. |
contentType |
string | Tipo do conteúdo associado ao objeto. |
metadata |
map<string, string> | Outros pares de chave/valor de metadados personalizados especificados pelo desenvolvedor. |
request.resource
contém tudo isso, exceto generation
,
metageneration
, etag
, timeCreated
e updated
.
Melhorar com o Cloud Firestore
É possível acessar os documentos no Cloud Firestore para avaliar outros critérios de autorização.
Usando as funções firestore.get()
e firestore.exists()
, sua regras de segurança podem avaliar solicitações recebidas em relação a documentos no Cloud Firestore.
As funções firestore.get()
e firestore.exists()
aguardam caminhos de documento totalmente especificados. Ao usar variáveis a fim de criar caminhos para firestore.get()
e firestore.exists()
, é preciso escapá-las explicitamente usando a sintaxe $(variable)
.
No exemplo abaixo, vemos uma regra que restringe o acesso de leitura a arquivos para esses usuários que são membros de clubes específicos.
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.id)).memberships } } }
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.id)) } } }
Depois de criar e salvar suas primeiras Cloud Storage Security Rules que usam essas funções do Cloud Firestore, você receberá uma solicitação no console do Firebase ou na CLI do Firebase para ativar permissões que conectam os dois produtos.
Para desativar o recurso, remova um papel do IAM conforme descrito em Gerenciar e implantar Firebase Security Rules.
Validar dados
As Firebase Security Rules para Cloud Storage também podem ser usadas para validar dados, incluindo validação do nome e do caminho do arquivo, bem como propriedades de metadados do arquivo, como contentType
e size
.
service firebase.storage { match /b/{bucket}/o { match /images/{imageId} { // Only allow uploads of any image file that's less than 5MB allow write: if request.resource.size < 5 * 1024 * 1024 && request.resource.contentType.matches('image/.*'); } } }
Funções personalizadas
À medida que suas Firebase Security Rules ficam mais complexas, recomendamos unir conjuntos de condições em funções que podem ser reutilizadas no seu conjunto de regras. As regras de segurança dão suporte a funções personalizadas. A sintaxe para funções personalizadas é um pouco parecida com JavaScript, mas as funções de Firebase Security Rules são escritas em uma linguagem de programação específica de domínio com algumas limitações importantes:
- As funções podem conter apenas uma única instrução
return
. Elas não podem conter nenhuma lógica adicional. Por exemplo, elas não podem executar loops ou chamar serviços externos. - As funções podem acessar automaticamente funções e variáveis do escopo em que são definidas. Por exemplo, uma função definida no escopo
service firebase.storage
tem acesso à variávelresource
e, apenas no Cloud Firestore, funções integradas, comoget()
eexists()
. - Elas podem chamar outras funções, mas não são executadas novamente. A profundidade total da pilha de chamadas é limitada a 10.
- Na versão
rules2
, as funções podem definir variáveis usando a palavra-chavelet
. As funções podem ter qualquer número de vinculações de permissão, mas precisam terminar com uma instrução de retorno.
Uma função é definida com a palavra-chave function
e usa zero ou mais argumentos. Por exemplo, pode ser necessário combinar os dois tipos de condição usados nos exemplos acima em uma única função:
service firebase.storage {
match /b/{bucket}/o {
// True if the user is signed in or the requested data is 'public'
function signedInOrPublic() {
return request.auth.uid != null || resource.data.visibility == 'public';
}
match /images/{imageId} {
allow read, write: if signedInOrPublic();
}
match /mp3s/{mp3Ids} {
allow read: if signedInOrPublic();
}
}
}
O uso de funções nas Firebase Security Rules torna essas funções mais fáceis de atualizar à medida que a complexidade das regras aumenta.
Próximas etapas
Após essa discussão das condições, você entende melhor as regras e está pronto para:
Saber lidar com os principais casos de uso e conhecer o fluxo de trabalho para desenvolver, testar e implantar regras:
- Escrever regras que abordam cenários comuns.
- Desenvolver seu conhecimento analisando as situações em que você precisa identificar e evitar regras não seguras.
- Testar as regras usando o emulador do Cloud Storage e a biblioteca de teste de regras de segurança dedicadas.
- Revisar os métodos disponíveis para implantar Rules.