API de regras de segurança do banco de dados do Firebase

Regra: Tipos

.ler

Concede a um cliente acesso de leitura a um local do Firebase Realtime Database.

Uma regra .read é um tipo de regra de segurança que concede a um cliente acesso de leitura a um local do Firebase Realtime Database. Por exemplo:

 ".read": "auth != null && auth.provider == 'twitter'"

O valor de uma regra .read é uma string, que é avaliada como um subconjunto da sintaxe de expressão do JavaScript com algumas mudanças comportamentais para aumentar a clareza e a correção. Uma regra .read que concede permissão para ler um local também permitirá a leitura de quaisquer descendentes desse local, mesmo que os descendentes tenham suas próprias regras .read que falhem.

Uma regra .read tem acesso a todas as variáveis ​​de regra do Firebase Realtime Database, exceto newData .

.escrever

Concede a um cliente acesso de gravação a um local do Firebase Realtime Database.

Uma regra .write é um tipo de regra de segurança que concede a um cliente acesso de gravação a um local do Firebase Realtime Database. Por exemplo:

".write": "auth != null && auth.token.isAdmin == true"

O valor de uma regra .write é uma string, que é avaliada como um subconjunto da sintaxe de expressão do JavaScript com algumas mudanças comportamentais para aumentar a clareza e a correção. Uma regra .write que concede permissão para gravar em um local também permitirá a gravação em qualquer descendente desse local, mesmo que os descendentes tenham suas próprias regras .write que falhem.

Uma regra .write tem acesso a todas as variáveis ​​de regra do Firebase Realtime Database.

.validar

Usado depois que uma regra .write concede acesso, para garantir que os dados que estão sendo gravados estejam em conformidade com um esquema específico.

Uma regra .validate é usada quando uma regra .write concede acesso, para garantir que os dados que estão sendo gravados estejam em conformidade com um padrão específico. Além de um .write conceder acesso, todas as regras .validate relevantes devem ser bem-sucedidas antes que uma gravação seja permitida. Por exemplo:

".validate": "newData.hasChildren(['name', 'age'])"

O valor de uma regra .validate é uma string, que é avaliada como um subconjunto da sintaxe de expressão do JavaScript com algumas mudanças comportamentais para aumentar a clareza e a correção.

Uma regra .validate tem acesso a todas as variáveis ​​de regra do Firebase Realtime Database.

.indexOn

Melhora o desempenho da consulta informando ao Firebase Realtime Database quais chaves você deseja que seus dados sejam indexados.

A regra .indexOn instrui os servidores do Firebase Realtime Database a indexar chaves específicas nos seus dados para melhorar o desempenho das suas consultas. Por exemplo, dado um banco de dados com uma coleção de dados de dinossauros, podemos dizer ao Firebase Realtime Database para otimizar as consultas, antes que elas sejam retornadas dos servidores, adicionando esta regra:

{
  "rules": {
    "dinosaurs": {
      ".indexOn": ["height", "length"]
    }
  }
}

Você pode encontrar mais informações sobre a regra .indexOn consultando a seção do guia de segurança sobre indexação de seus dados .

Regra: Variáveis

autenticação

Uma variável que contém a carga do token se um cliente for autenticado ou null se o cliente não estiver autenticado.

O Firebase Realtime Database permite que você se autentique facilmente em vários provedores integrados e gere tokens de autenticação para eles. Depois que um usuário for autenticado com um dos provedores integrados, a variável auth conterá o seguinte:

Campo Descrição
provider O método de autenticação utilizado (por exemplo, “senha”, “anônimo”, “facebook”, “github”, “google” ou “twitter”).
uid Um ID de usuário exclusivo, garantido como único em todos os provedores.
token O conteúdo do token do Firebase Auth ID. Veja auth.token .

Como exemplo, poderíamos ter uma regra como a seguinte para permitir que os usuários criem comentários, desde que armazenem seu ID de usuário com o comentário:

{
  "rules": {
    ".read": true,
    "$comment": {
      ".write": "!data.exists() && newData.child('user_id').val() == auth.uid"
    }
  }
}

Também poderíamos criar uma regra como a seguinte para permitir que os usuários criem comentários, desde que estejam conectados no Facebook:

{
  "rules": {
    ".read": true,
    "$comment": {
      ".write": "!data.exists() && auth.provider == 'facebook'"
    }
  }
}

auth.token

Uma variável que contém o conteúdo do token do Firebase Auth ID.

O 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, auth.token também conterá quaisquer declarações personalizadas especificadas pelo desenvolvedor.

Todos esses valores podem ser usados ​​dentro das regras. Por exemplo, para restringir o acesso às contas do Google associadas a um endereço gmail.com, poderíamos adicionar a regra:

{
  "rules": {
    ".read": "auth != null",
    "gmailUsers": {
      "$uid": {
        ".write": "auth.token.email_verified == true && auth.token.email.matches(/.*@gmail.com$/)"
      }
    }
  }
}

Para completar, os campos a seguir também estão incluídos em auth.token , mas é improvável que sejam úteis para regras.

Campo Descrição
iss O emissor do token.
aud O público do token.
auth_time A última vez que o usuário se autenticou com uma credencial usando o dispositivo que recebeu o token.
iat A hora em que o token foi emitido.
exp A hora em que o token expira.

$localização

Uma variável que pode ser usada para fazer referência à chave de um $location que foi usada anteriormente em uma estrutura de regras.

Quando você tem um $location em sua estrutura de regras, você pode usar uma variável $ correspondente em sua expressão de regra para obter o nome do filho real que está sendo lido ou escrito. Então, suponha que queiramos dar a cada usuário acesso de leitura e gravação ao seu próprio /users/<user> local. Poderíamos usar:

{
  "rules": {
    "users": {
      "$user": {
        ".read": "auth.uid === $user",
        ".write": "auth.uid === $user"
      }
    }
  }
}

Quando um cliente tenta acessar /users/barney , o local padrão $user corresponderá com $user sendo igual a "barney". Portanto, a regra .read verificará se auth.uid === 'barney' . Como resultado, a leitura /users/barney só será bem-sucedida se o cliente for autenticado com um uid de "barney".

agora

Contém o número de milissegundos desde a época Unix de acordo com os servidores do Firebase Realtime Database.

A variável now contém o número de milissegundos desde a época do UNIX, de acordo com os servidores do Firebase Realtime Database. Por exemplo, você pode usar isso para validar que o horário created de um usuário nunca seja definido como um horário no futuro:

{
  "rules": {
    "users": {
      "$user": {
        "created": {
          ".validate": "newData.val() < now"
        }
      }
    }
  }
}

raiz

Um RuleDataSnapshot correspondente aos dados atuais na raiz do seu Firebase Realtime Database.

A variável root fornece um RuleDataSnapshot correspondente aos dados atuais na raiz do seu Firebase Realtime Database. Você pode usar isso para ler quaisquer dados do seu banco de dados nas suas expressões de regras. Por exemplo, se quisermos permitir que os usuários leiam /comments somente se seu /users/<id>/active estiver definido como true, poderíamos usar:

{
  "rules": {
    "comments": {
      ".read": "root.child('users').child(auth.uid).child('active').val() == true"
    }
  }
}

Então, se /users/barney/active contivesse o valor true, um usuário autenticado com um uid "barney" poderia gravar no nó /comments .

dados

Um RuleDataSnapshot correspondente aos dados atuais no Firebase Realtime Database no local da regra em execução no momento.

A variável data fornece um RuleDataSnapshot correspondente aos dados atuais no local do banco de dados da regra atualmente em execução (em oposição a root, que fornece os dados da raiz do seu banco de dados).

Por exemplo, se você quiser permitir que qualquer cliente acesse /users/<user> se /users/<user>/public estiver definido como true, você poderá usar:

{
  "rules": {
    "users": {
      "$user": {
        ".read": "data.child('public').val() == true"
      }
    }
  }
}

A variável data está disponível nas regras .read , .write e .validate .

novos dados

Um RuleDataSnapshot correspondente aos dados que resultarão se a gravação for permitida.

Para regras .write e .validate , a variável newData fornece um RuleDataSnapshot correspondente aos dados que resultarão se a gravação for permitida (é uma "fusão" dos dados existentes mais os novos dados que estão sendo gravados). Então, se você quiser garantir que cada usuário tenha nome e idade, você pode usar:

{
  "rules": {
    "users": {
      "$user": {
        ".read": true,
        ".write": true,
        ".validate": "newData.hasChildren(['name', 'age'])"
      }
    }
  }
}

Como newData mescla dados existentes e novos dados, ele se comporta adequadamente mesmo para atualizações "parciais". Por exemplo:

var fredRef = firebase.database().ref("users/fred");
// Valid since we have a name and age.
fredRef.set({ name: "Fred", age: 19 });
// Valid since we are updating the name but there's already an age.
fredRef.child("age").set(27);
// Invalid since the .validate rule will no longer be true.
fredRef.child("name").remove();

A variável newData não está disponível nas regras .read , pois não há novos dados sendo gravados. Você deve apenas usar data .

RuleDataSnapshot: Métodos

val()

Obtém o valor primitivo ( string , number , boolean ou null ) deste RuleDataSnapshot .

Valor de retorno : ( String , Number , Boolean , Null ) - O valor primitivo deste RuleDataSnapshot .

Ao contrário de DataSnapshot.val() , chamar val() em um RuleDataSnapshot que possui dados filhos não retornará um objeto contendo os filhos. Em vez disso, retornará um valor sentinela especial. Isso garante que as regras sempre possam operar de forma extremamente eficiente.

Como consequência, você deve sempre usar child() para acessar filhos (por exemplo data.child('name').val() , não data.val().name ).

Este exemplo só permite a leitura se o filho isReadable estiver definido como true no local que está sendo lido.

".read": "data.child('isReadable').val() == true"

criança()

Obtém um RuleDataSnapshot para o local no caminho relativo especificado.

Argumentos : childPath String - Um caminho relativo para a localização dos dados filho.

Valor de retorno : RuleDataSnapshot – O RuleDataSnapshot para o local filho.

O caminho relativo pode ser um nome filho simples (por exemplo, 'fred') ou um caminho mais profundo separado por barras (por exemplo, 'fred/nome/primeiro'). Se o local filho não tiver dados, um RuleDataSnapshot vazio será retornado.

Este exemplo só permite a leitura se o filho isReadable estiver definido como true no local que está sendo lido.

".read": "data.child('isReadable').val() == true"

pai()

Obtém um RuleDataSnapshot para o local pai.

Valor de retorno : RuleDataSnapshot – O RuleDataSnapshot para o local pai.

Se esta instância se referir à raiz do seu Firebase Realtime Database, ela não terá pai e parent() falhará, fazendo com que a expressão da regra atual seja ignorada (como uma falha).

Este exemplo só permite a leitura se o irmão isReadable estiver definido como verdadeiro.

".read": "data.parent().child('isReadable').val() == true"

hasChild(caminhofilho)

Retorna verdadeiro se o filho especificado existir.

Argumentos : childPath String - Um caminho relativo para a localização de um filho em potencial.

Valor de retorno : Boolean - true se existirem dados no caminho filho especificado; senão false .

Este exemplo só permite que os dados sejam gravados se contiverem um "nome" filho.

".validate": "newData.hasChild('name')"

temCrianças([crianças])

Verifica a existência de crianças.

Argumentos : children Array opcional - Um array de chaves filhas que devem existir.

Valor de retorno : Boolean - true se os filhos (especificados) existirem; senão false .

Se nenhum argumento for fornecido, ele retornará verdadeiro se o RuleDataSnapshot tiver algum filho. Se uma matriz de nomes de filhos for fornecida, ela retornará true somente se todos os filhos especificados existirem no RuleDataSnapshot .

Este exemplo só permite que os dados sejam gravados se contiverem um ou mais filhos.

".validate": "newData.hasChildren()"

Este exemplo só permite que os dados sejam gravados se contiverem filhos de “nome” e “idade”.

".validate": "newData.hasChildren(['name', 'age'])"

existe()

Retornará verdadeiro se este RuleDataSnapshot contiver algum dado.

Valor de retorno : Boolean - true se o RuleDataSnapshot contiver algum dado; senão false .

A função existe retorna verdadeiro se este RuleDataSnapshot contiver algum dado. É puramente uma função de conveniência, pois data.exists() é equivalente a data.val() != null .

Este exemplo permite uma gravação neste local, desde que não haja dados existentes.

".write": "!data.exists()"

getPrioridade()

Obtém a prioridade dos dados em um RuleDataSnapshot .

Valor de retorno : ( String , Number , Null ) - A prioridade dos dados neste RuleDataSnapshot .

Este exemplo garante que os novos dados que estão sendo gravados tenham prioridade

".validate": "newData.getPriority() != null"

éNúmero()

Retornará verdadeiro se este RuleDataSnapshot contiver um valor numérico.

Valor de retorno : Boolean - true se os dados forem numéricos; senão false .

Este exemplo garante que os novos dados que estão sendo gravados tenham "idade" filha com um valor numérico.

".validate": "newData.child('age').isNumber()"

éString()

Retornará verdadeiro se este RuleDataSnapshot contiver um valor de string.

Valor de retorno : Boolean - true se os dados forem uma String ; senão false .

Este exemplo garante que os novos dados que estão sendo gravados tenham um "nome" filho com um valor de string.

".validate": "newData.child('name').isString()

éBoolean()

Retornará verdadeiro se este RuleDataSnapshot contiver um valor booleano.

Valor de retorno : Booleantrue se os dados forem Boolean ; senão false .

Este exemplo garante que os novos dados que estão sendo gravados tenham um filho "ativo" com um valor booleano.

".validate": "newData.child('active').isBoolean()"

Sequência: Propriedades

comprimento

Retorna o comprimento da string.

Valor de retorno : Number - O número de caracteres na string.

Este exemplo requer que a string tenha pelo menos 10 caracteres.

".validate": "newData.isString() && newData.val().length >= 10"

String: Métodos

contém (substring)

Retornará verdadeiro se a string contiver a substring especificada.

Argumentos : substring String - Uma substring a ser procurada.

Valor de retorno : Boolean - true se a string contiver a substring especificada; senão false .

Este exemplo requer que os dados sejam uma string contendo "@".

".validate": "newData.isString() && newData.val().contains('@')"

começaCom(substring)

Retornará verdadeiro se a string começar com a substring especificada.

Argumentos : substring String - Uma substring a ser procurada no início.

Valor de retorno : Boolean - true se a string contiver a substring especificada; senão false .

Este exemplo permite acesso de leitura se auth.token.identifier começar com "internal-"

".read": "auth.token.identifier.beginsWith('internal-')"

terminaCom(substring)

Retornará verdadeiro se a string terminar com a substring especificada.

Argumentos : substring String - Uma substring a ser procurada no final.

Valor de retorno : Boolean - true se a string terminar com a substring especificada; senão false .

Este exemplo permite acesso de leitura se auth.token.identifier terminar com "@company.com"

".read": "auth.token.identifier.endsWith('@company.com')"

substituir(substring, substituição)

Retorna uma cópia da string com todas as instâncias de uma substring especificada substituídas pela string de substituição especificada.

Argumentos : substring String - Uma substring a ser procurada. replacement String - Uma string para substituir a substring.

Valor de retorno : String - A nova string após substituir a substring pela substituição.

O método replace() difere um pouco do método replace() do JavaScript porque substitui todas as instâncias de uma substring especificada pela string de substituição especificada, não apenas a primeira instância.

Como os pontos não são permitidos nas chaves, precisamos escapar das strings com pontos antes de armazená-las. Um exemplo disso seria com endereços de e-mail. Suponha que tenhamos uma lista de endereços de e-mail na lista de permissões em nosso nó /whitelist/ :

{
 "user": {
   "$uid": {
     "email": <email>
   }
 },
 "whitelist": {
   "fred@gmail%2Ecom": true,
   "barney@aol%2Ecom": true
 }
}

Podemos criar uma regra que só permita que usuários sejam adicionados se seu e-mail estiver no nó /whitelist/ :

{
  "rules": {
    "users": {
      "$uid": {
        ".read": "true",
        ".write": "root.child('whitelist').child(newData.child('email').val().replace('.', '%2E')).exists()"
      }
    }
  }
}

paraLowerCase()

Retorna uma cópia da string convertida em minúsculas.

Valor de retorno : String - A string convertida em minúsculas.

Este exemplo permite acesso de leitura se auth.token.identifier , pois todas as letras minúsculas existirem em /users .

".read": "root.child('users').child(auth.token.identifier.toLowerCase()).exists()"

paraUpperCase()

Retorna uma cópia da string convertida em maiúsculas.

Valor de retorno : String - A string convertida em maiúsculas.

Este exemplo permite acesso de leitura se auth.token.identifier , pois todas as letras maiúsculas existirem em /users .

".read": "root.child('users').child(auth.token.identifier.toUpperCase()).exists()"

correspondências (regex)

Retorna verdadeiro se a string corresponder ao literal de expressão regular especificado.

Valor de retorno : Boolean - true se a string corresponder ao literal da expressão regular, regex; senão false .

Veja a documentação completa de regras regex .

Operadores

+ (acrescentar)

Usado para adicionar variáveis ​​ou para concatenação de strings.

O exemplo a seguir garante que o novo valor aumente o valor existente em exatamente um. Isso é útil para implementar um contador:

".write": "newData.val() === data.val() + 1"
".validate": "root.child('room_names/' + $room_id).exists()"

- (negar ou subtrair)

Usado para negar um valor ou subtrair dois valores em uma expressão de regras.

Esta regra de validação verifica se o novo valor é o inverso de um valor filho no local:

".validate": "newData.val() === -(data.child('quantity').val())"

O exemplo a seguir usa subtração para garantir que apenas as mensagens dos últimos dez minutos possam ser lidas:

".read": "newData.child('timestamp').val() > (now - 600000)"

* (multiplicar)

Usado para multiplicar variáveis ​​em uma expressão de regras.

Esta regra de validação verifica se o novo valor é igual ao produto do preço e da quantidade (dois valores existentes):

".validate": "newData.val() === data.child('price').val() * data.child('quantity').val()"

/ (dividir)

Usado para dividir variáveis ​​em uma expressão de regras.

No exemplo a seguir, a regra de validação garante que os dados armazenados sejam a média do total de dados armazenados em outro lugar:

".validate": "newData.val() === data.parent().child('sum').val() / data.parent().child('numItems').val()"

% (módulo)

Usado para encontrar o restante da divisão de uma variável por outra em uma expressão de regras.

Esta regra valida que apenas números pares podem ser escritos:

".validate": "newData.val() % 2 === 0"

=== (igual)

Usado para verificar se duas variáveis ​​em uma expressão de regras têm o mesmo tipo e valor.

A regra a seguir usa o operador === para conceder acesso de gravação somente ao proprietário da conta do usuário. O uid do usuário deve corresponder exatamente à chave ( $user_id ) para que a regra seja avaliada como verdadeira.

"users": {
  ".write": "$user_id === auth.uid"
}

!== (não é igual)

Usado para verificar se duas variáveis ​​em uma expressão de regras não são iguais.

A seguinte regra de leitura garante que apenas usuários logados possam ler dados:

".read": "auth !== null"

&& (E)

Avalia como verdadeiro se ambos os operandos forem verdadeiros. Usado para avaliar diversas condições em uma expressão de regras.

A regra de validação a seguir verifica se os novos dados são uma string com menos de 100 caracteres:

".validate": "newData.isString() && newData.val().length < 100"

|| (OU)

Avaliado como verdadeiro se um operando na expressão de regras for verdadeiro.

Neste exemplo, podemos escrever desde que não existam dados antigos ou novos. Em outras palavras, podemos escrever se estamos excluindo ou criando dados, mas não atualizando dados.

".write": "!data.exists() || !newData.exists()"

! (NÃO)

Avalia como verdadeiro se seu único operando for falso. Nas expressões de regras, o ! O operador é frequentemente usado para verificar se os dados foram gravados em um local.

A regra a seguir só permite acesso de gravação se não houver dados no local especificado:

".write": "!data.exists()"

> (maior que)

Usado para verificar se um valor é maior que outro valor em uma expressão de regras.

Esta regra de validação verifica se a string que está sendo escrita não é uma string vazia:

".validate": "newData.isString() && newData.val().length > 0"

< (menos que)

Usado para verificar se um valor é menor que outro valor em uma expressão de regras.

Esta regra de validação verifica se uma string tem menos de 20 caracteres:

".validate": "newData.isString() && newData.val().length < 20"

>= (maior ou igual a)

Usado para verificar se um valor é maior ou igual a outro valor em uma expressão de regras.

Esta regra de validação verifica se a string que está sendo escrita não é uma string vazia:

".validate": "newData.isString() && newData.val().length >= 1"

<= (menor ou igual a)

Usado para verificar se um valor é menor ou igual a outro valor em uma expressão de regras.

Esta regra de validação garante que novos dados não possam ser adicionados no futuro:

".validate": "newData.val() <= now"

? (operador ternário)

Usado para avaliar uma expressão de regras condicionais.

O operador ternário leva três operandos. O operando antes do ? é a condição. Se a condição for avaliada como verdadeira, o segundo operando será avaliado. Se a condição for falsa, o terceiro operando é avaliado.

Para a seguinte regra de validação, o novo valor pode ser um número ou um booleano. Se for um número, deve ser maior que 0.

".validate": "newData.isNumber() ? newData.val() > 0 : newData.isBoolean()"