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 alterações 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 falham.

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

.Escreva

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á gravar em qualquer descendente desse local, mesmo que os descendentes tenham suas próprias regras .write que falham.

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 alterações 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 em seus dados para melhorar o desempenho de 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 obter mais informações sobre a regra .indexOn consultando a seção do guia de segurança sobre como indexar seus dados .

Regra: Variáveis

autenticação

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

O Firebase Realtime Database permite que você autentique facilmente 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 usado (por exemplo, "senha", "anônimo", "facebook", "github", "google" ou "twitter").
uid Um ID de usuário exclusivo, com garantia de exclusividade em todos os provedores.
token O conteúdo do token de ID de autenticação do Firebase. Consulte 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 usando o Facebook:

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

autenticação.token

Uma variável que contém o conteúdo do token de ID de autenticação do Firebase.

O token contém algumas ou todas as seguintes chaves:

Campo Descrição
email O endereço de e-mail associado à conta, se houver.
email_verified true se o usuário tiver verificado que tem acesso ao endereço de email -mail. Alguns provedores verificam automaticamente os endereços de e-mail que possuem.
phone_number O número de telefone associado à conta, se houver.
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 entrada 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 de regras. Por exemplo, para restringir o acesso às contas do Google associadas a um endereço gmail.com, podemos 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 provavelmente não serão ú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 referenciar a chave de um $location que foi usado anteriormente em uma estrutura de regras.

Quando você tem um $location em sua estrutura de regras, você pode usar uma variável $ correspondente dentro de sua expressão de regra para obter o nome do filho real que está sendo lido ou escrito. Então, suponha que queremos dar a cada usuário acesso de leitura e gravação à sua própria localização /users/<user> . 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 de $user corresponderá com $user sendo igual a "barney". Portanto, a regra .read verificará se auth.uid === 'barney' . Como resultado, a leitura de /users/barney terá sucesso somente se o cliente for autenticado com um uid de "barney".

agora

Contém o número de milissegundos desde a época do 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 a hora de created de um usuário nunca está definida para uma hora no futuro:

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

raiz

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

A variável raiz fornece um RuleDataSnapshot correspondente aos dados atuais na raiz do Firebase Realtime Database. Você pode usar isso para ler quaisquer dados em seu banco de dados em suas expressões de regra. Por exemplo, se quisermos permitir que os usuários leiam /comments apenas se /users/<id>/active estiver definido como verdadeiro, podemos 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 de "barney" poderia gravar no nó /comments .

dados

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

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

Então, 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 de dados está disponível nas .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 sendo gravados). Então, se você quiser garantir que cada usuário tenha um 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 porque não há novos dados sendo gravados. Você deve apenas usar dados .

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 tenha dados filho não retornará um objeto contendo os filhos. Em vez disso, ele 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"

filho()

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

Argumentos : childPath String - Um caminho relativo para o local 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 essa instância se referir à raiz do Firebase Realtime Database, ela não terá pai e parent() falhará, fazendo com que a expressão de regra atual seja ignorada (como uma falha).

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

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

hasChild(childPath)

Retorna true se o filho especificado existir.

Argumentos : childPath String - Um caminho relativo para o local 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')"

temFilhos([filhos])

Verifica a existência de filhos.

Argumentos : children Array opcional - Uma matriz de chaves filhas que devem existir.

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

Se nenhum argumento for fornecido, ele retornará true 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 "name" e "age".

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

existe()

Retorna true se este RuleDataSnapshot contiver quaisquer dados.

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

A função existe retornará true se este RuleDataSnapshot contiver quaisquer dados. É 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()"

getPriority()

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()

Retorna true 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" filho com um valor numérico.

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

isString()

Retorna true 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()

isBoolean()

Retorna true se este RuleDataSnapshot contiver um valor booleano.

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

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

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

Cadeia: 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)

Retorna true 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)

Retorna true 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)

Retorna true 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ída 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 a substituição da substring pela substituição.

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

Como os períodos não são permitidos nas chaves, precisamos escapar de strings com pontos antes de armazená-los. 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ó permite que usuários sejam adicionados se seus e-mails estiverem no nó /whitelist/ :

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

toLowerCase()

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

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

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

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

toUpperCase()

Retorna uma cópia da string convertida para maiúscula.

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

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

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

correspondências (regex)

Retorna true 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 do regex de regras .

Operadores

+ (acrescentar)

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

O exemplo a seguir garante que o novo valor incremente 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 a 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 de preço e 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 apenas ao proprietário da conta de 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"
}

!== (diferente)

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 várias condições em uma expressão de regras.

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

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

|| (OU)

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

Neste exemplo, podemos escrever desde que os dados antigos ou novos não existam. 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. Em expressões de regras, o ! O operador geralmente é usado para ver 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"

< (menor 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.

Essa 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 recebe 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 regra de validação a seguir, 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()"