Proteger dados do usuário

As regras de segurança do Firebase para Cloud Storage estão integradas com o Firebase Authentication para fornecer ao Storage uma autenticação eficiente baseada em usuários. Isso permite o controle de acesso granular com base em reivindicações de um token do Authentication.

Autenticação do usuário

Quando um usuário autenticado executa uma solicitação no Cloud Storage, a variável request.auth é preenchida com o uid (request.auth.uid) do usuário, bem como as declarações JWT do Firebase Authentication (request.auth.token).

Além disso, ao usar a autenticação personalizada, outras reivindicações são exibidas no campo request.auth.token.

Quando um usuário não autenticado realiza uma solicitação, a variável request.auth é null.

Com esses dados, há várias maneiras comuns de usar a autenticação para proteger os arquivos:

  • Público: ignora request.auth
  • Privado autenticado: verifica se request.auth não é null
  • Privado por usuário: verifica se request.auth.uid é igual a um caminho uid
  • Privado por grupo: verifica as reivindicações do token personalizado para confirmar se elas correspondem a uma reivindicação escolhida ou lê os metadados do arquivo para ver se existe um campo de metadados

Público

Qualquer regra que não considere o contexto request.auth pode ser considerada uma regra public, pois não considera o contexto de autenticação do usuário. Essas regras podem ser úteis para expor dados públicos, como recursos do jogo, arquivos de som ou outros conteúdos estáticos.

// Anyone to read a public image if the file is less than 100kB
// Anyone can upload a public file ending in '.txt'
match /public/{imageId} {
  allow read: if resource.size < 100 * 1024;
  allow write: if imageId.matches(".*\\.txt");
}

Privado autenticado

Em determinados casos, os dados devem ser visíveis somente para os usuários autenticados do seu aplicativo. Como a variável request.auth é null para todos os usuários não autenticados, basta verificar se a variável request.auth existe para exigir autenticação:

// Require authentication on all internal image reads
match /internal/{imageId} {
  allow read: if request.auth != null;
}

Privado por usuário

De longe, o caso de uso mais comum para request.auth será conceder permissões granulares aos arquivos para cada usuário, desde o upload de imagens de perfil até a leitura de documentos particulares.

Como os arquivos do Cloud Storage têm um caminho completo até o arquivo, para permitir que um usuário controle um arquivo, basta uma informação exclusiva que identifique o usuário no caminho (como o uid do usuário). Essa informação pode ser verificada quando a regra é avaliada:

// Only a user can upload their profile picture, but anyone can view it
match /users/{userId}/profilePicture.png {
  allow read;
  allow write: if request.auth != null && request.auth.uid == userId;
}

Privado por grupo

Outro caso de uso igualmente comum é conceder permissões de acesso a um objeto para um grupo. Por exemplo, permitir que vários membros da equipe colaborem em um documento compartilhado. Há várias abordagens para fazer isso, como:

  • produzir um token personalizado do Firebase Authentication que contenha informações adicionais sobre um membro do grupo (por exemplo, um código do grupo);
  • incluir informações do grupo (como um ID do grupo ou uma lista de uids autorizados) nos metadados do arquivo.

Depois que esses dados são armazenados no token ou nos metadados do arquivo, ele pode ser referenciado dentro de uma regra:

// Allow reads if the group ID in your token matches the file metadata's `owner` property
// Allow writes if the group ID is in the user's custom token
match /files/{groupId}/{fileName} {
  allow read: if resource.metadata.owner == request.auth.token.groupId;
  allow write: if request.auth.token.groupId == groupId;
}

Exemplo completo

Veja no exemplo abaixo casos simples dos quatro tipos comuns de restrições de autenticação:

service firebase.storage {
  match /b/{bucket}/o {
    match /images {
      // Anyone can view any image (no auth, publicly readable)
      match /{allImages=**} {
        allow read;
      }

      // Only authenticated users can write to "public" images
      match /public/{imageId} {
        allow write: if request.auth != null;
      }

      // Only an individual user can write to "their" images
      match /{userId}/{imageId} {
        allow write: if request.auth.uid == userId;
      }

      // Allow a "group" of users to read/write to shared images
      // An owner metadata property on the object contains the groupId for reads
      // A custom token has been minted with a groupId property for writes
      match /{groupId}/{imageId} {
        allow read: if resource.metadata.owner == request.auth.token.groupId;
        allow write: if request.auth.token.groupId == groupId;
      }
    }
  }
}