API Firebase Database Security Rules

Regra: tipos

.read

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

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

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

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

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

.write

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

A 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. Exemplo:

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

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

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

.validate

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

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

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

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

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

.indexOn

Melhora o desempenho da consulta informando ao Firebase Realtime Database quais chaves você quer 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 consultas. Por exemplo, considerando um banco de dados com uma coleção de dados de dinossauros, podemos instruir o Firebase Realtime Database a otimizar as consultas antes que elas sejam retornadas dos servidores. Para isso, basta adicionar esta regra:

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

Saiba mais sobre a regra .indexOn na seção do guia de segurança sobre como indexar seus dados.

Regra: variáveis

auth

Uma variável contendo o payload do token, se um cliente estiver autenticado ou null se o cliente não estiver autenticado.

Com o Firebase Realtime Database, você pode se autenticar facilmente em vários provedores integrados e gerar tokens de autenticação para eles. Depois que um usuário for autenticado com um dos provedores integrados, a variável de autenticação vai 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 código de usuário único em todos os provedores.
token O conteúdo do token de ID do Firebase Auth. 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 podemos 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'"
    }
  }
}

token de autenticação

Uma variável com o conteúdo do token de ID do Firebase Auth.

O token contém algumas ou todas as chaves a seguir:

Campo Descrição
email O endereço de e-mail associado à conta, se essa informação existir.
email_verified true se o usuário tiver verificado que tem acesso ao endereço email. Alguns provedores verificam automaticamente esses endereços de e-mail.
phone_number O número de telefone associado à conta, se essa informação existir.
name O nome de exibição do usuário, se ele tiver sido definido.
sub O UID do Firebase do usuário. Ele é exclusivo dentro de um projeto.
firebase.identities O dicionário de todas as identidades associadas à conta desse 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 de 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 receber esse token. Pode ser uma das seguintes strings: custom, password, phone, anonymous, google.com, facebook.com, github.com ou twitter.com.
firebase.tenant O ID do locatário associado à conta, se houver. Por exemplo, tenant2-m6tyz.

Se você estiver usando a autenticação personalizada, auth.token também conterá qualquer reivindicações especificadas pelo desenvolvedor.

Todos esses valores podem ser usados dentro de regras. Por exemplo, para restringir o acesso a 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 maior abrangência, 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 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.

$location

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 na estrutura das regras, é possível usar uma variável $ correspondente na expressão de regra para saber o nome do filho que está sendo lido ou gravado. Suponha que queremos dar a cada usuário acesso de leitura e gravação ao próprio local /users/<user>. Poderíamos usar:

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

Quando um cliente tentar acessar /users/barney, o local padrão $user corresponderá ao $user sendo igual a "barney". Portanto, a regra .read vai verificar se auth.uid === 'barney'. Como resultado, a leitura de /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, é possível usar isso para validar que o horário created de um usuário nunca está definido como um horário no futuro:

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

root

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, para permitir que os usuários leiam /comments somente se a /users/<id>/active estiver definida como verdadeira, 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" 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 (em oposição ao "root", que fornece os dados da raiz do banco de dados).

Por exemplo, para permitir que qualquer cliente acesse /users/<user> caso /users/<user>/public seja definido como verdadeiro, use:

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

A variável de dados está disponível em .read, .write e .validate.

newData

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

Para as regras .write e .validate, a variável newData fornece um RuleDataSnapshot correspondente aos dados que serão gerados se a gravação for permitida, ou seja, uma "mesclagem" dos dados atuais e dos novos dados que estão sendo gravados. Então, se você quiser garantir que cada usuário tenha um nome e idade, pode usar:

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

Como newData mescla dados existentes e novos, ele se comporta corretamente mesmo para dados "parciais" atualizações. 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 usar apenas dados.

RuleDataSnapshot: métodos

Função val()

Recebe o valor primitivo (string, number, boolean ou null) deste RuleDataSnapshot.

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

Ao contrário de DataSnapshot.val(), chamar val() em um RuleDataSnapshot que tem dados filhos não retornará um objeto com os filhos. Em vez disso, ela retornará um valor de sentinela especial. Isso garante que as regras sempre funcionem de maneira extremamente eficiente.

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

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

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

filho()

Recebe um RuleDataSnapshot para o local no caminho relativo especificado.

Argumentos: childPath String: caminho relativo para o local dos dados filhos.

Valor de retorno: RuleDataSnapshot – o RuleDataSnapshot do local do filho.

O caminho relativo pode ser um nome filho simples (por exemplo, "fred") ou um caminho mais profundo separado por barras (por exemplo, "fred/name/first"). 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 verdadeiro no local que está sendo lido.

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

pai()

Recebe um RuleDataSnapshot para o local pai.

Valor de retorno: RuleDataSnapshot – o RuleDataSnapshot do local pai.

Se essa instância se referir à raiz do seu Firebase Realtime Database, ela não terá um 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 verdadeiro.

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

hasChild(childPath)

Retorna true se o filho especificado existir.

Argumentos: childPath String: caminho relativo para o local de um filho em potencial.

Valor de retorno: Booleano - true se os dados existirem no caminho filho especificado. caso contrário, false.

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

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

hasChildren([children])

Verifica a existência de filhos.

Argumentos: children Array opcional: uma matriz de chaves filhas que precisam existir.

Valor de retorno: Boolean - true se houver filhos (o especificado); caso contrário, false.

Se nenhum argumento for fornecido, ele retornará "true" se 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 "name" e "idade" crianças.

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

existe(),

Retorna verdadeiro se este RuleDataSnapshot contém algum dado.

Valor de retorno: Boolean - true se o RuleDataSnapshot contiver dados; caso contrário, false.

A função existe retorna como verdadeiro se este RuleDataSnapshot contém algum dado. É uma função meramente de conveniência, já que data.exists() é equivalente a data.val() != null.

O exemplo permite uma gravação nesse local, desde que não haja dados.

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

getPrioridade().

Recebe a prioridade dos dados em um RuleDataSnapshot.

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

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

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

isNumber()

Retorna verdadeiro se este RuleDataSnapshot contém um valor numérico.

Valor de retorno: Boolean - true se os dados forem numéricos; caso contrário, false.

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

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

Função isString().

Retorna verdadeiro se este RuleDataSnapshot contém um valor de string.

Valor de retorno: Boolean - true se os dados forem String; caso contrário, false.

Este exemplo garante que os novos dados gravados tenham "name" filho com um valor de string.

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

Função isBoolean()

Retorna verdadeiro se este RuleDataSnapshot contém um valor booleano.

Valor de retorno: Boolean - true se os dados forem Boolean; caso contrário, false.

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

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

String: propriedades

comprimento

Retorna o comprimento da string.

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

Este exemplo exige 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 contém a substring especificada.

Argumentos: substring String: substring a ser procurada.

Valor de retorno: Boolean - true se a string contiver a substring especificada; caso contrário, false.

Este exemplo exige que os dados sejam uma string que contenha "@".

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

começaWith(substring)

Retorna true se a string começa 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; caso contrário, false.

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

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

termina com(substring)

Retorna true se a string termina 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; caso contrário, false.

Este exemplo permite acesso de leitura se auth.token.identifier terminar com "@empresa.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 depois de substituir a substring por substituição.

O método replace() é um pouco diferente do método replace() 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 pontos finais não são permitidos nas chaves, precisamos fazer o escape de 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 permitidos no 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 o e-mail deles estiver 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 para letras minúsculas.

Valor de retorno: String: a string convertida para letras minúsculas.

Este exemplo permite o acesso de leitura se auth.token.identifier, já que todas as letras minúsculas existem em /users.

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

toUpperCase()

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

Valor de retorno: String: a string convertida para letras maiúsculas.

Esse exemplo permite acesso de leitura se auth.token.identifier, já que todas as letras maiúsculas existem em /users.

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

corresponde(regex)

Retorna true se a string corresponde ao literal de expressão regular especificado.

Valor de retorno: Boolean - true se a string corresponder ao literal de expressão regular, regex. caso contrário, false.

Veja a documentação completa sobre regex de regras.

Operadores

+ (adicionar)

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

O exemplo a seguir garante que o novo valor incremente o atual 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 à produção 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 gravados:

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

=== (é igual a)

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 de usuário. O UID do usuário precisa corresponder exatamente à chave ($user_id) para que a regra seja avaliada como verdadeira.

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

!== (não é igual a)

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

A regra de leitura a seguir garante que apenas usuários conectados possam ler os dados:

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

&& (E)

Avalia como verdadeiro se ambos operandos forem verdadeiros. Usado para avaliar várias 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)

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

Neste exemplo, podemos gravar desde que não existam dados antigos ou novos. Em outras palavras, podemos gravar ao excluir ou criar dados, mas não atualizar os dados.

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

! (SEM)

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

A regra a seguir só permite o 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.

A regra de validação verifica se a string que está sendo gravada 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.

A regra de validação verifica se a string que está sendo gravada 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 usa 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 será avaliado.

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

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