Linguagem das regras de segurança

As regras de segurança do Firebase usam linguagens flexíveis, avançadas e personalizadas que têm suporte a uma ampla variedade de complexidade e granularidade. É possível tornar suas regras tão específicas ou gerais quanto fizer sentido para seu aplicativo. As regras do Realtime Database usam uma sintaxe semelhante a JavaScript em uma estrutura JSON. As regras do Cloud Firestore e do Cloud Storage usam uma linguagem baseada na Common Expression Language (CEL), criada com base nas instruções match e allow compatíveis com o acesso condicional.

No entanto, como essas linguagens são personalizadas, há uma curva de aprendizado. Use este guia para entender melhor a linguagem das regras conforme você lidar mais com regras mais complexas.

Selecione um produto para saber mais sobre as regras dele.

Estrutura básica

Cloud Firestore

As regras de segurança do Firebase no Cloud Firestore e no Cloud Storage usam as seguintes estrutura e sintaxe:

service <<name>> {
  // Match the resource path.
  match <<path>> {
    // Allow the request if the following conditions are true.
    allow <<methods>> : if <<condition>>
  }
}

Veja abaixo os principais conceitos que você precisa conhecer antes de criar as regras.

  • Solicitação: o método ou os métodos invocados na instrução allow que você permite serem executados. Os métodos padrão são: get, list, create, update e delete. Os métodos de conveniência read e write permitem amplo acesso de leitura e gravação no banco de dados ou caminho de armazenamento especificado.
  • Caminho: o banco de dados ou o local de armazenamento, representado como um caminho de URI.
  • Regra: a instrução allow, que inclui uma condição que permite uma solicitação se ela for avaliada como verdadeira.

Cada um desses conceitos é descrito em mais detalhes abaixo.

Cloud Storage

As regras de segurança do Firebase no Cloud Firestore e no Cloud Storage usam as seguintes estrutura e sintaxe:

service <<name>> {
  // Match the resource path.
  match <<path>> {
    // Allow the request if the following conditions are true.
    allow <<methods>> : if <<condition>>
  }
}

Veja abaixo os principais conceitos que você precisa conhecer antes de criar as regras.

  • Solicitação: o método ou os métodos invocados na instrução allow que você permite serem executados. Os métodos padrão são: get, list, create, update e delete. Os métodos de conveniência read e write permitem amplo acesso de leitura e gravação no banco de dados ou caminho de armazenamento especificado.
  • Caminho: o banco de dados ou o local de armazenamento, representado como um caminho de URI.
  • Regra: a instrução allow, que inclui uma condição que permite uma solicitação se ela for avaliada como verdadeira.

Cada um desses conceitos é descrito em mais detalhes abaixo.

Realtime Database

No Realtime Database, as regras de segurança do Firebase consistem em expressões semelhantes a JavaScript contidas em um documento JSON.

Elas usam a seguinte sintaxe:

{
  "rules": {
    "<<path>>": {
    // Allow the request if the condition for each method is true.
      ".read": <<condition>>,
      ".write": <<condition>>,
      ".validate": <<condition>>
    }
  }
}

Existem três elementos básicos na regra:

  • Caminho: o local do banco de dados. Ele corresponde à estrutura JSON do seu banco de dados.
  • Solicitação: são os métodos que a regra usa para conceder acesso. As regras read e write concedem amplo acesso de leitura e gravação, enquanto as regras validate atuam como uma verificação secundária para conceder acesso com base nos dados recebidos ou atuais.
  • Condição: a condição que permitirá uma solicitação se ela for avaliada como verdadeira.

Blocos de regras

Cloud Firestore

Veja a seguir os elementos básicos de uma regra no Cloud Firestore e no Cloud Storage:

  • A declaração service: declara o produto do Firebase ao qual as regras se aplicam.
  • O bloco match: define um caminho no banco de dados ou no intervalo de armazenamento ao qual as regras se aplicam.
  • A instrução allow: fornece condições para conceder acesso, diferenciadas por métodos. Os métodos compatíveis incluem: get, list, create, update, delete e os métodos de conveniência read e write.
  • Declarações function opcionais: permitem combinar e unir condições para uso em várias regras.

O service contém um ou mais blocos match com instruções allow que fornecem condições que concedem acesso a solicitações. As variáveis request e resource estão disponíveis para uso nas condições da regra. A linguagem das regras de segurança do Firebase também é compatível com declarações function.

Versão da sintaxe

A instrução syntax indica a versão da linguagem de regras do Firebase usada para gravar a origem. A versão mais recente da linguagem é v2.

rules_version = '2';
service cloud.firestore {
...
}

Se nenhuma instrução rules_version for fornecida, suas regras serão avaliadas usando o mecanismo v1.

Serviço

A declaração service define a qual produto ou serviço do Firebase suas regras se aplicam. Só é possível incluir uma declaração service por arquivo de origem.

Cloud Firestore

service cloud.firestore {
 // Your 'match' blocks with their corresponding 'allow' statements and
 // optional 'function' declarations are contained here
}

Cloud Storage

service firebase.storage {
  // Your 'match' blocks with their corresponding 'allow' statements and
  // optional 'function' declarations are contained here
}

Se estiver definindo regras para o Cloud Firestore e o Cloud Storage usando a CLI do Firebase, será necessário mantê-las em arquivos separados.

Correspondência

Um bloco match declara um padrão path que corresponde ao caminho da operação solicitada (o request.path recebido). O corpo do match precisa ter um ou mais blocos match aninhados, instruções allow ou declarações function. O caminho nos blocos match aninhados é relativo ao caminho no bloco match pai.

O padrão path é um nome semelhante a um diretório que pode incluir variáveis ou caracteres curinga. O padrão path permite correspondências de segmento de caminho único e de vários caminhos. Todas as variáveis vinculadas em um path são visíveis no escopo match ou em qualquer escopo aninhado em que o path é declarado.

As correspondências com um padrão path podem ser parciais ou completas:

  • Correspondências parciais: o padrão path é uma correspondência de prefixo do request.path.
  • Correspondências completas: o padrão path corresponde a todo o request.path.

Quando uma correspondência completa ocorre, as regras dentro do bloco são avaliadas. Quando uma correspondência parcial é feita, as regras match aninhadas são testadas para ver se algum path aninhado concluirá a correspondência.

As regras em cada match completo são avaliadas para determinar se a solicitação será permitida. Se qualquer regra correspondente conceder acesso, a solicitação será permitida. Se nenhuma regra correspondente conceder acesso, a solicitação será negada.

// Given request.path == /example/hello/nested/path the following
// declarations indicate whether they are a partial or complete match and
// the value of any variables visible within the scope.
service firebase.storage {
  // Partial match.
  match /example/{singleSegment} {   // `singleSegment` == 'hello'
    allow write;                     // Write rule not evaluated.
    // Complete match.
    match /nested/path {             // `singleSegment` visible in scope.
      allow read;                    // Read rule is evaluated.
    }
  }
  // Complete match.
  match /example/{multiSegment=**} { // `multiSegment` == /hello/nested/path
    allow read;                      // Read rule is evaluated.
  }
}

Como mostra o exemplo acima, as declarações path aceitam as seguintes variáveis:

  • Caractere curinga de segmento único: uma variável de caractere curinga é declarada em um caminho ao colocar uma variável entre chaves: {variable}. Essa variável pode ser acessada na instrução match como um string.
  • Caractere curinga recursivo: o caractere curinga recursivo, ou de vários segmentos, corresponde a vários segmentos em um caminho ou abaixo dele. Ele corresponde a todos os caminhos abaixo do local para o qual você o definiu. É possível declará-lo adicionando a string =** ao final da variável de segmento: {variable=**}. Essa variável pode ser acessada na instrução match como um objeto path.

Allow

O bloco match contém uma ou mais instruções allow. Essas são as regras de fato. É possível aplicar regras allow a um ou mais métodos. As condições em uma instrução allow precisam ser avaliadas como verdadeiras para que o Cloud Firestore ou o Cloud Storage conceda qualquer solicitação recebida. Também é possível escrever instruções allow sem condições, por exemplo, allow read. No entanto, se a instrução allow não incluir uma condição, ela sempre permitirá a solicitação desse método.

Se alguma das regras allow do método for atendida, a solicitação será permitida. Além disso, se uma regra mais ampla conceder acesso, as regras concederão acesso e ignorarão as mais específicas que possam limitá-lo.

Veja o exemplo a seguir, em que qualquer usuário pode ler ou excluir os próprios arquivos. Uma regra mais granular só permite gravações se o usuário que solicitar a gravação for o proprietário do arquivo e o arquivo for um PNG. Um usuário pode excluir qualquer arquivo no subcaminho, mesmo que ele não seja PNG, porque a regra anterior permite isso.

service firebase.storage {
  // Allow the requestor to read or delete any resource on a path under the
  // user directory.
  match /users/{userId}/{anyUserFile=**} {
    allow read, delete: if request.auth != null && request.auth.uid == userId;
  }

  // Allow the requestor to create or update their own images.
  // When 'request.method' == 'delete' this rule and the one matching
  // any path under the user directory would both match and the `delete`
  // would be permitted.

  match /users/{userId}/images/{imageId} {
    // Whether to permit the request depends on the logical OR of all
    // matched rules. This means that even if this rule did not explicitly
    // allow the 'delete' the earlier rule would have.
    allow write: if request.auth != null && request.auth.uid == userId && imageId.matches('*.png');
  }
}

Método

Cada instrução allow inclui um método que concede acesso para solicitações recebidas do mesmo método.

Método Tipo de solicitação
Métodos de conveniência
read Qualquer tipo de solicitação de leitura
write Qualquer tipo de solicitação de gravação
Métodos padrão
get Ler solicitações de documentos ou arquivos únicos
list Ler solicitações de consultas e conjuntos
create Gravar novos documentos ou arquivos
update Gravar em documentos existentes do banco de dados ou atualizar metadados de arquivos;
delete Excluir dados

Não é possível sobrepor métodos de leitura no mesmo bloco match ou métodos de gravação conflitantes na mesma declaração path.

Por exemplo, as seguintes regras apresentariam falha:

service bad.example {
  match /rules/with/overlapping/methods {
    // This rule allows reads to all authenticated users
    allow read: if request.auth != null;

    match another/subpath {
      // This secondary, more specific read rule causes an error
      allow get: if request.auth != null && request.auth.uid == "me";
      // Overlapping write methods in the same path cause an error as well
      allow write: if request.auth != null;
      allow create: if request.auth != null && request.auth.uid == "me";
    }
  }
}

Função

À medida que suas regras de segurança se tornam mais complexas, recomendamos reunir conjuntos de condições em funções que possam 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 regras de segurança 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 cloud.firestore tem acesso à variável resource e às funções integradas como get() e exists().
  • Elas podem chamar outras funções, mas não são executadas novamente. A profundidade total da pilha de chamadas é limitada a 20.
  • Na versão v2 das regras, as funções podem definir variáveis usando a palavra-chave let. As funções podem ter até 10 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 cloud.firestore {
  match /databases/{database}/documents {
    // 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 /cities/{city} {
      allow read, write: if signedInOrPublic();
    }

    match /users/{user} {
      allow read, write: if signedInOrPublic();
    }
  }
}

Veja um exemplo que mostra argumentos de função e permite atribuições. As declarações de atribuição precisam ser separadas por ponto e vírgula.

function isAuthorOrAdmin(userId, article) {
  let isAuthor = article.author == userId;
  let isAdmin = exists(/databases/$(database)/documents/admins/$(userId));
  return isAuthor || isAdmin;
}

Observe como a atribuição isAdmin aplica uma pesquisa da coleção de administradores. Para uma avaliação lenta sem a necessidade de pesquisas desnecessárias, aproveite a natureza de curto prazo das comparações && (AND) e || (OR) para chamar uma segunda função somente se isAuthor for mostrado como verdadeiro (para comparações &&) ou falso (para comparações ||).

function isAdmin(userId) {
  return exists(/databases/$(database)/documents/admins/$(userId));
}
function isAuthorOrAdmin(userId, article) {
  let isAuthor = article.author == userId;
  // `||` is short-circuiting; isAdmin called only if isAuthor == false.
  return isAuthor || isAdmin(userId);
}

O uso de funções nas regras de segurança as torna mais fáceis de atualizar à medida que a complexidade delas aumenta.

Cloud Storage

Veja a seguir os elementos básicos de uma regra no Cloud Firestore e no Cloud Storage:

  • A declaração service: declara o produto do Firebase ao qual as regras se aplicam.
  • O bloco match: define um caminho no banco de dados ou no intervalo de armazenamento ao qual as regras se aplicam.
  • A instrução allow: fornece condições para conceder acesso, diferenciadas por métodos. Os métodos compatíveis incluem: get, list, create, update, delete e os métodos de conveniência read e write.
  • Declarações function opcionais: permitem combinar e unir condições para uso em várias regras.

O service contém um ou mais blocos match com instruções allow que fornecem condições que concedem acesso a solicitações. As variáveis request e resource estão disponíveis para uso nas condições da regra. A linguagem das regras de segurança do Firebase também é compatível com declarações function.

Versão da sintaxe

A instrução syntax indica a versão da linguagem de regras do Firebase usada para gravar a origem. A versão mais recente da linguagem é v2.

rules_version = '2';
service cloud.firestore {
...
}

Se nenhuma instrução rules_version for fornecida, suas regras serão avaliadas usando o mecanismo v1.

Serviço

A declaração service define a qual produto ou serviço do Firebase suas regras se aplicam. Só é possível incluir uma declaração service por arquivo de origem.

Cloud Firestore

service cloud.firestore {
 // Your 'match' blocks with their corresponding 'allow' statements and
 // optional 'function' declarations are contained here
}

Cloud Storage

service firebase.storage {
  // Your 'match' blocks with their corresponding 'allow' statements and
  // optional 'function' declarations are contained here
}

Se estiver definindo regras para o Cloud Firestore e o Cloud Storage usando a CLI do Firebase, será necessário mantê-las em arquivos separados.

Correspondência

Um bloco match declara um padrão path que corresponde ao caminho da operação solicitada (o request.path recebido). O corpo do match precisa ter um ou mais blocos match aninhados, instruções allow ou declarações function. O caminho nos blocos match aninhados é relativo ao caminho no bloco match pai.

O padrão path é um nome semelhante a um diretório que pode incluir variáveis ou caracteres curinga. O padrão path permite correspondências de segmento de caminho único e de vários caminhos. Todas as variáveis vinculadas em um path são visíveis no escopo match ou em qualquer escopo aninhado em que o path é declarado.

As correspondências com um padrão path podem ser parciais ou completas:

  • Correspondências parciais: o padrão path é uma correspondência de prefixo do request.path.
  • Correspondências completas: o padrão path corresponde a todo o request.path.

Quando uma correspondência completa ocorre, as regras dentro do bloco são avaliadas. Quando uma correspondência parcial é feita, as regras match aninhadas são testadas para ver se algum path aninhado concluirá a correspondência.

As regras em cada match completo são avaliadas para determinar se a solicitação será permitida. Se qualquer regra correspondente conceder acesso, a solicitação será permitida. Se nenhuma regra correspondente conceder acesso, a solicitação será negada.

// Given request.path == /example/hello/nested/path the following
// declarations indicate whether they are a partial or complete match and
// the value of any variables visible within the scope.
service firebase.storage {
  // Partial match.
  match /example/{singleSegment} {   // `singleSegment` == 'hello'
    allow write;                     // Write rule not evaluated.
    // Complete match.
    match /nested/path {             // `singleSegment` visible in scope.
      allow read;                    // Read rule is evaluated.
    }
  }
  // Complete match.
  match /example/{multiSegment=**} { // `multiSegment` == /hello/nested/path
    allow read;                      // Read rule is evaluated.
  }
}

Como mostra o exemplo acima, as declarações path aceitam as seguintes variáveis:

  • Caractere curinga de segmento único: uma variável de caractere curinga é declarada em um caminho ao colocar uma variável entre chaves: {variable}. Essa variável pode ser acessada na instrução match como um string.
  • Caractere curinga recursivo: o caractere curinga recursivo, ou de vários segmentos, corresponde a vários segmentos em um caminho ou abaixo dele. Ele corresponde a todos os caminhos abaixo do local para o qual você o definiu. É possível declará-lo adicionando a string =** ao final da variável de segmento: {variable=**}. Essa variável pode ser acessada na instrução match como um objeto path.

Allow

O bloco match contém uma ou mais instruções allow. Essas são as regras de fato. É possível aplicar regras allow a um ou mais métodos. As condições em uma instrução allow precisam ser avaliadas como verdadeiras para que o Cloud Firestore ou o Cloud Storage conceda qualquer solicitação recebida. Também é possível escrever instruções allow sem condições, por exemplo, allow read. No entanto, se a instrução allow não incluir uma condição, ela sempre permitirá a solicitação desse método.

Se alguma das regras allow do método for atendida, a solicitação será permitida. Além disso, se uma regra mais ampla conceder acesso, as regras concederão acesso e ignorarão as mais específicas que possam limitá-lo.

Veja o exemplo a seguir, em que qualquer usuário pode ler ou excluir os próprios arquivos. Uma regra mais granular só permite gravações se o usuário que solicitar a gravação for o proprietário do arquivo e o arquivo for um PNG. Um usuário pode excluir qualquer arquivo no subcaminho, mesmo que ele não seja PNG, porque a regra anterior permite isso.

service firebase.storage {
  // Allow the requestor to read or delete any resource on a path under the
  // user directory.
  match /users/{userId}/{anyUserFile=**} {
    allow read, delete: if request.auth != null && request.auth.uid == userId;
  }

  // Allow the requestor to create or update their own images.
  // When 'request.method' == 'delete' this rule and the one matching
  // any path under the user directory would both match and the `delete`
  // would be permitted.

  match /users/{userId}/images/{imageId} {
    // Whether to permit the request depends on the logical OR of all
    // matched rules. This means that even if this rule did not explicitly
    // allow the 'delete' the earlier rule would have.
    allow write: if request.auth != null && request.auth.uid == userId && imageId.matches('*.png');
  }
}

Método

Cada instrução allow inclui um método que concede acesso para solicitações recebidas do mesmo método.

Método Tipo de solicitação
Métodos de conveniência
read Qualquer tipo de solicitação de leitura
write Qualquer tipo de solicitação de gravação
Métodos padrão
get Ler solicitações de documentos ou arquivos únicos
list Ler solicitações de consultas e conjuntos
create Gravar novos documentos ou arquivos
update Gravar em documentos existentes do banco de dados ou atualizar metadados de arquivos;
delete Excluir dados

Não é possível sobrepor métodos de leitura no mesmo bloco match ou métodos de gravação conflitantes na mesma declaração path.

Por exemplo, as seguintes regras apresentariam falha:

service bad.example {
  match /rules/with/overlapping/methods {
    // This rule allows reads to all authenticated users
    allow read: if request.auth != null;

    match another/subpath {
      // This secondary, more specific read rule causes an error
      allow get: if request.auth != null && request.auth.uid == "me";
      // Overlapping write methods in the same path cause an error as well
      allow write: if request.auth != null;
      allow create: if request.auth != null && request.auth.uid == "me";
    }
  }
}

Função

À medida que suas regras de segurança se tornam mais complexas, recomendamos reunir conjuntos de condições em funções que possam 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 regras de segurança 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 cloud.firestore tem acesso à variável resource e às funções integradas como get() e exists().
  • Elas podem chamar outras funções, mas não são executadas novamente. A profundidade total da pilha de chamadas é limitada a 20.
  • Na versão v2 das regras, as funções podem definir variáveis usando a palavra-chave let. As funções podem ter até 10 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 cloud.firestore {
  match /databases/{database}/documents {
    // 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 /cities/{city} {
      allow read, write: if signedInOrPublic();
    }

    match /users/{user} {
      allow read, write: if signedInOrPublic();
    }
  }
}

Veja um exemplo que mostra argumentos de função e permite atribuições. As declarações de atribuição precisam ser separadas por ponto e vírgula.

function isAuthorOrAdmin(userId, article) {
  let isAuthor = article.author == userId;
  let isAdmin = exists(/databases/$(database)/documents/admins/$(userId));
  return isAuthor || isAdmin;
}

Observe como a atribuição isAdmin aplica uma pesquisa da coleção de administradores. Para uma avaliação lenta sem a necessidade de pesquisas desnecessárias, aproveite a natureza de curto prazo das comparações && (AND) e || (OR) para chamar uma segunda função somente se isAuthor for mostrado como verdadeiro (para comparações &&) ou falso (para comparações ||).

function isAdmin(userId) {
  return exists(/databases/$(database)/documents/admins/$(userId));
}
function isAuthorOrAdmin(userId, article) {
  let isAuthor = article.author == userId;
  // `||` is short-circuiting; isAdmin called only if isAuthor == false.
  return isAuthor || isAdmin(userId);
}

O uso de funções nas regras de segurança as torna mais fáceis de atualizar à medida que a complexidade delas aumenta.

Realtime Database

Conforme descrito acima, as regras do Realtime Database incluem três elementos básicos: o local do banco de dados como um espelho da estrutura JSON do banco de dados, o tipo de solicitação e a condição que concederá acesso.

Local do banco de dados

A estrutura das regras precisa seguir a estrutura dos dados que você armazenou no banco. Por exemplo, em um aplicativo de bate-papo com uma lista de mensagens, é possível ter dados como estes:

  {
    "messages": {
      "message0": {
        "content": "Hello",
        "timestamp": 1405704370369
      },
      "message1": {
        "content": "Goodbye",
        "timestamp": 1405704395231
      },
      ...
    }
  }

Suas regras precisam espelhar essa estrutura. Exemplo:

  {
    "rules": {
      "messages": {
        "$message": {
          // only messages from the last ten minutes can be read
          ".read": "data.child('timestamp').val() > (now - 600000)",

          // new messages must have a string content and a number timestamp
          ".validate": "newData.hasChildren(['content', 'timestamp']) &&
                        newData.child('content').isString() &&
                        newData.child('timestamp').isNumber()"
        }
      }
    }
  }

Como mostra o exemplo acima, as regras do Realtime Database são compatíveis com uma variável $location para corresponder a segmentos de caminho. Use o prefixo $ na frente do seu segmento de caminho para corresponder sua regra a qualquer nó filho no caminho.

  {
    "rules": {
      "rooms": {
        // This rule applies to any child of /rooms/, the key for each room id
        // is stored inside $room_id variable for reference
        "$room_id": {
          "topic": {
            // The room's topic can be changed if the room id has "public" in it
            ".write": "$room_id.contains('public')"
          }
        }
      }
    }
  }

Também é possível usar o $variable em paralelo com nomes de caminho constantes.

  {
    "rules": {
      "widget": {
        // a widget can have a title or color attribute
        "title": { ".validate": true },
        "color": { ".validate": true },

        // but no other child paths are allowed
        // in this case, $other means any key excluding "title" and "color"
        "$other": { ".validate": false }
      }
    }
  }

Método

No Realtime Database, existem três tipos de regra. Dois desses tipos de regra, read e write, se aplicam ao método de uma solicitação recebida. O tipo de regra validate aplica estruturas de dados e valida o formato e o conteúdo dos dados. As regras executam regras .validate depois de verificar se uma regra .write concede acesso.

Tipos de regra
.read Descreve se e quando os dados podem ser lidos pelos usuários.
.write Descreve se e quando os dados podem ser gravados.
.validate Define a formatação correta do valor, o tipo de dados e se o valor tem atributos filhos.

Por padrão, o acesso a um caminho será negado se não houver uma regra que permita esse acesso.

Condições de criação

Cloud Firestore

Uma condição é uma expressão booleana que determina se uma operação específica deve ser permitida ou negada. As variáveis request e resource fornecem contexto para essas condições.

A variável request

A variável request inclui os seguintes campos e informações correspondentes:

request.auth

Um JSON Web Token (JWT) que contém credenciais de autenticação do Firebase Authentication. O token auth contém um conjunto de declarações padrão e quaisquer declarações personalizadas criadas por meio do Firebase Authentication. Saiba mais sobre as regras de segurança do Firebase e o Firebase Authentication.

request.method

O request.method pode ser qualquer um dos métodos padrão ou um método personalizado. Os métodos de conveniência read e write também existem para simplificar as regras de gravação que se aplicam a todos os métodos padrão somente leitura ou somente gravação, respectivamente.

request.params

O request.params inclui todos os dados não relacionados especificamente ao request.resource que podem ser úteis para avaliação. Na prática, nesse mapa, os métodos padrão precisam estar vazios e os métodos personalizados devem conter dados que não sejam recursos. É necessário cuidado para que os serviços não renomeiem nem modifiquem o tipo de qualquer chave ou valor apresentados como parâmetros.

request.path

O request.path é o caminho do resource de destino. O caminho é relativo ao serviço. Os segmentos de caminho que contém caracteres seguros sem uso do URL, como /, são codificados em URL.

A variável resource

O resource é o valor atual no serviço representado como um mapa de pares de chave-valor. Referir-se a resource em uma condição resultará em, no máximo, uma leitura do valor do serviço. Essa consulta contará em qualquer cota relacionada ao serviço do recurso. Para solicitações get, o resource só será contabilizado na cota na negação.

Operadores e precedência do operador

Use a tabela abaixo como referência para os operadores e a precedência correspondente deles nas regras do Cloud Firestore e do Cloud Storage.

Expressões arbitrárias fornecidas a e b, um campo f e um índice i.

Operador Descrição Associatividade
a[i] a() a.f Índice, chamada, acesso ao campo da esquerda para a direita
!a -a Negação unária da direita para a esquerda
a/b a%b a*b Operadores multiplicativos da esquerda para a direita
a+b a-b Operadores aditivos da esquerda para a direita
a>b a>=b a<=b Operadores relacionais da esquerda para a direita
a in b Existência na lista ou no mapa da esquerda para a direita
a is type Comparação de tipos, em que type pode ser bool, int, float, number, string, list, map, timestamp, duration, path ou latlng da esquerda para a direita
a==b a!=b Operadores de comparação da esquerda para a direita
a && b Condicional E da esquerda para a direita
a || b Condicional OU da esquerda para a direita
a ? true_value : false_value Expressão ternária da esquerda para a direita

Cloud Storage

Uma condição é uma expressão booleana que determina se uma operação específica deve ser permitida ou negada. As variáveis request e resource fornecem contexto para essas condições.

A variável request

A variável request inclui os seguintes campos e informações correspondentes:

request.auth

Um JSON Web Token (JWT) que contém credenciais de autenticação do Firebase Authentication. O token auth contém um conjunto de declarações padrão e quaisquer declarações personalizadas criadas por meio do Firebase Authentication. Saiba mais sobre as regras de segurança do Firebase e o Firebase Authentication.

request.method

O request.method pode ser qualquer um dos métodos padrão ou um método personalizado. Os métodos de conveniência read e write também existem para simplificar as regras de gravação que se aplicam a todos os métodos padrão somente leitura ou somente gravação, respectivamente.

request.params

O request.params inclui todos os dados não relacionados especificamente ao request.resource que podem ser úteis para avaliação. Na prática, nesse mapa, os métodos padrão precisam estar vazios e os métodos personalizados devem conter dados que não sejam recursos. É necessário cuidado para que os serviços não renomeiem nem modifiquem o tipo de qualquer chave ou valor apresentados como parâmetros.

request.path

O request.path é o caminho do resource de destino. O caminho é relativo ao serviço. Os segmentos de caminho que contém caracteres seguros sem uso do URL, como /, são codificados em URL.

A variável resource

O resource é o valor atual no serviço representado como um mapa de pares de chave-valor. Referir-se a resource em uma condição resultará em, no máximo, uma leitura do valor do serviço. Essa consulta contará em qualquer cota relacionada ao serviço do recurso. Para solicitações get, o resource só será contabilizado na cota na negação.

Operadores e precedência do operador

Use a tabela abaixo como referência para os operadores e a precedência correspondente deles nas regras do Cloud Firestore e do Cloud Storage.

Expressões arbitrárias fornecidas a e b, um campo f e um índice i.

Operador Descrição Associatividade
a[i] a() a.f Índice, chamada, acesso ao campo da esquerda para a direita
!a -a Negação unária da direita para a esquerda
a/b a%b a*b Operadores multiplicativos da esquerda para a direita
a+b a-b Operadores aditivos da esquerda para a direita
a>b a>=b a<=b Operadores relacionais da esquerda para a direita
a in b Existência na lista ou no mapa da esquerda para a direita
a is type Comparação de tipos, em que type pode ser bool, int, float, number, string, list, map, timestamp, duration, path ou latlng da esquerda para a direita
a==b a!=b Operadores de comparação da esquerda para a direita
a && b Condicional E da esquerda para a direita
a || b Condicional OU da esquerda para a direita
a ? true_value : false_value Expressão ternária da esquerda para a direita

Realtime Database

Uma condição é uma expressão booleana que determina se uma operação específica deve ser permitida ou negada. É possível definir essas condições nas regras do Realtime Database das seguintes maneiras.

Variáveis predefinidas

Há diversas variáveis úteis e predefinidas que podem ser acessadas dentro de uma definição de regras. Veja um breve resumo de cada uma:

Variáveis predefinidas
now O horário atual em milissegundos desde a era Linux. Isso funciona muito bem para validar carimbos de data/hora criados com o firebase.database.ServerValue.timESTAMP do SDK.
root Um RuleDataSnapshot que representa o caminho raiz no banco de dados do Firebase como ele existia antes da tentativa de operação.
newData Um RuleDataSnapshot que representa os dados como eles existiriam após a tentativa de operação. Inclui os novos dados que estão sendo gravados e dados atuais.
data Um RuleDataSnapshot que representa os dados como eles existiam antes da tentativa de operação.
$ variables Um caminho curinga usado para representar códigos e chaves filhas dinâmicas.
auth Representa o payload do token de um usuário autenticado.

Essas variáveis podem ser usadas em qualquer lugar nas suas regras. Por exemplo, as regras de segurança abaixo garantem que os dados gravados no nó /foo/ precisam ser uma string com menos de 100 caracteres:

{
  "rules": {
    "foo": {
      // /foo is readable by the world
      ".read": true,

      // /foo is writable by the world
      ".write": true,

      // data written to /foo must be a string less than 100 characters
      ".validate": "newData.isString() && newData.val().length < 100"
    }
  }
}

Regras com base em dados

Todos os dados no seu banco podem ser usados nas regras. Usando as variáveis predefinidas root, data e newData, é possível acessar qualquer caminho como ele existiria antes ou depois de um evento de gravação.

Considere este exemplo, que permite operações de gravação, desde que o valor do nó /allow_writes/ seja true, o nó pai não tenha uma sinalização readOnly definido e haja um filho chamado foo nos dados recém-gravados:

".write": "root.child('allow_writes').val() === true &&
          !data.parent().child('readOnly').exists() &&
          newData.child('foo').exists()"

Regras com base em consultas

Embora não seja possível usar regras como filtros, você pode limitar o acesso a subconjuntos de dados usando parâmetros de consulta nas suas regras. Use as expressões query. nas regras para conceder acesso de leitura ou de gravação com base nos parâmetros de consulta.

Por exemplo, a regra baseada em consulta a seguir usa regras de segurança baseadas em usuário e regras baseadas em consulta para restringir o acesso aos dados na coleção baskets apenas aos carrinhos de compras do usuário ativo:

"baskets": {
  ".read": "auth.uid !== null &&
            query.orderByChild === 'owner' &&
            query.equalTo === auth.uid" // restrict basket access to owner of basket
}

A seguinte consulta, que inclui os parâmetros de consulta na regra, seria bem-sucedida:

db.ref("baskets").orderByChild("owner")
                 .equalTo(auth.currentUser.uid)
                 .on("value", cb)                 // Would succeed

No entanto, as consultas que não incluem os parâmetros na regra falhariam com um erro PermissionDenied:

db.ref("baskets").on("value", cb)                 // Would fail with PermissionDenied

Você também pode usar regras baseadas em consulta para limitar a quantidade de dados que um cliente baixa por meio das operações de leitura.

Por exemplo, a seguinte regra limita o acesso de leitura somente aos primeiros 1.000 resultados de uma consulta, ordenados por prioridade:

messages: {
  ".read": "query.orderByKey &&
            query.limitToFirst <= 1000"
}

// Example queries:

db.ref("messages").on("value", cb)                // Would fail with PermissionDenied

db.ref("messages").limitToFirst(1000)
                  .on("value", cb)                // Would succeed (default order by key)

As expressões query. a seguir estão disponíveis nas regras de segurança do Realtime Database.

Expressões de regra baseada em consulta
Expressão Tipo Descrição
query.orderByKey
query.orderByPriority
query.orderByValue
boolean Verdadeiro para consultas ordenadas por chave, prioridade ou valor. Falso, em outros casos.
query.orderByChild string
null
Usa uma string para representar o caminho relativo para um nó filho. Por exemplo: query.orderByChild === "address/zip" Se a consulta não for ordenada por um nó filho, esse valor é nulo.
query.startAt
query.endAt
query.equalTo
string
number
boolean
null
Recupera os limites da consulta em execução ou, se não houver limite definido, retorna nulo.
query.limitToFirst
query.limitToLast
number
null
Recupera o limite na consulta em execução ou, se não houver limite definido, retorna nulo.

Operadores

As regras do Realtime Database são compatíveis com um número de operadores que podem ser usados para combinar variáveis na instrução de condição. Veja a lista completa de operadores na documentação de referência.

Como criar condições

Suas condições reais variam de acordo com o acesso que você quer conceder. As regras oferecem intencionalmente um grau enorme de flexibilidade, de modo que as regras do seu aplicativo possam ser tão simples ou complexas quanto for necessário.

Para saber mais sobre como criar regras simples e prontas para produção, consulte Regras básicas de segurança.