← Guias por stack

Firebase

Segurança para a tua app com Firebase

A segurança do Firebase depende quase por completo das regras que escreves. Com as regras em modo de teste ou demasiado abertas, a tua base de dados fica ao alcance de qualquer um. Revê isto antes de abrir a tua app.

Riscos típicos em Firebase

Regras em modo de teste

O modo de teste permite leitura e escrita a toda a gente. Muita gente lança sem o mudar, deixando a base de dados completamente aberta.

Confundir a chave pública com segurança

A config do Firebase é pública por design; o que protege os teus dados são as regras, não esconder essa chave. Assumir o contrário leva a dados expostos.

Outras chaves no frontend

Juntamente com a config do Firebase costumam colar-se chaves que são mesmo secretas (pagamentos, email, IA). Essas nunca devem estar no JavaScript do navegador.

"Segurança no Firebase" são duas coisas que convém separar. A primeira é o modelo do Firebase: o navegador fala diretamente com a base de dados e o armazenamento, por isso não há um servidor a filtrar, e a proteção vive nas regras, no App Check e na configuração do projeto. A segunda é o que o Lovable, o Bolt ou o Cursor fazem com o Firebase ao gerar código, que é de onde vêm quase todos os buracos. Este guia explica o modelo, repassa o que a IA faz mal, deixa-te um firebase.json e umas regras base para colar, um prompt de revisão e a verificação de fora. Os dez erros de regras mais comuns, com a regra má e a boa, estão em os erros de segurança mais comuns no Firebase.

Parte 1: como funciona a segurança no Firebase

O cliente fala com os serviços, não com o teu servidor

Numa app Firebase típica não há backend próprio: o SDK do navegador lê e escreve no Firestore, no Realtime Database e no Storage diretamente. Isso significa que o objeto de configuração com apiKey e projectId é público por desenho (identifica o projeto, não autoriza nada) e que a única barreira entre um visitante e os teus dados são as regras de segurança. Cada produto tem as suas: Firestore, Realtime Database e Storage configuram-se separadamente, e uma app costuma ter aberto o que ninguém olhou.

As regras respondem a "quem pode o quê"

Uma regra recebe o pedido com o utilizador autenticado (request.auth), o documento que se quer ler ou escrever e os dados novos (request.resource.data). Com isso decide. A distinção chave é entre autenticado (há sessão) e autorizado (essa sessão pode ver esse documento): request.auth != null só verifica o primeiro, e registar-se é grátis. As regras também validam o que se escreve, para que um utilizador não se ponha isAdmin: true no próprio perfil.

O que protege além das regras

  • App Check. Exige que os pedidos venham da tua app real (com reCAPTCHA ou Play Integrity) e não de um script com o teu projectId. Trava o abuso e as faturas inesperadas por leituras massivas.
  • Restrição da chave de API. Na consola do Google Cloud, limita a chave aos domínios do teu site e às APIs que usas. Não substitui as regras, mas fecha uma porta.
  • Auth. Domínios autorizados para o início de sessão, proteção contra enumeração de emails, verificação de email, só os métodos de acesso que realmente usas, autenticação multifator se lidas com dados sensíveis.
  • Cloud Functions como servidor. Tudo o que precise de uma chave secreta (pagamentos, email, IA) vai numa função, com o segredo no Secret Manager, e o cliente chama a função. Atenção: uma função HTTP é pública para toda a internet a menos que verifiques o token do utilizador ou uses uma função callable com App Check.
  • Orçamento. O Firebase cobra por leitura e por invocação. Alertas de orçamento no Google Cloud e limites nas regras (request.query.limit) evitam que um ciclo ou um atacante te deixem uma fatura.

Hosting: o que o Firebase põe e o que não põe

O Firebase Hosting dá TLS automático, CDN e redirecionamento para HTTPS. Não põe cabeçalhos de segurança: acrescentam-se no firebase.json. E serve tudo o que esteja na pasta pública, incluindo um .env copiado por engano.

Parte 2: o que a IA faz mal com o Firebase

  • Regras em modo de teste, e depois if true. A IA deixa as regras que abrem tudo durante trinta dias; ao expirarem, a app falha e a solução rápida é abri-las para sempre.
  • request.auth != null como única condição. Qualquer utilizador registado lê os dados de todos os outros.
  • Escritas sem validar. O perfil tem role ou credits e a regra de update não exclui esses campos.
  • Outras chaves no bundle. Junto à configuração do Firebase aparecem a chave secreta do Stripe, a da OpenAI ou a de um serviço de email. Detalhe em segredos que a tua app deixa fugir no navegador.
  • Funções HTTP sem verificar o utilizador. A função que cobra, envia emails ou chama um modelo responde a qualquer pessoa que conheça o URL.
  • Storage com regras copiadas do Firestore. allow read, write: if request.auth != null em storage.rules: qualquer utilizador lê os ficheiros dos outros e carrega o que quiser.
  • Sem App Check, sem cabeçalhos, sem alertas. Três caixas que ninguém marca porque a app "já funciona".

Um bloco para colar no teu projeto

Cabeçalhos de segurança no firebase.json (a Content-Security-Policy vai à parte porque depende dos teus scripts):

{
  "hosting": {
    "public": "dist",
    "headers": [
      {
        "source": "**",
        "headers": [
          { "key": "Strict-Transport-Security", "value": "max-age=63072000; includeSubDomains; preload" },
          { "key": "X-Content-Type-Options", "value": "nosniff" },
          { "key": "X-Frame-Options", "value": "DENY" },
          { "key": "Referrer-Policy", "value": "strict-origin-when-cross-origin" },
          { "key": "Permissions-Policy", "value": "camera=(), microphone=(), geolocation=()" }
        ]
      }
    ]
  }
}

E um ponto de partida para firestore.rules: tudo fechado por defeito, cada utilizador o seu documento e campos de privilégio protegidos.

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /users/{userId} {
      allow read: if request.auth != null && request.auth.uid == userId;
      allow create: if request.auth != null && request.auth.uid == userId
        && !request.resource.data.keys().hasAny(['role', 'isAdmin', 'plan', 'credits']);
      allow update: if request.auth != null && request.auth.uid == userId
        && !request.resource.data.diff(resource.data).affectedKeys()
           .hasAny(['role', 'isAdmin', 'plan', 'credits']);
    }
    match /{document=**} {
      allow read, write: if false;
    }
  }
}

Acrescenta depois uma regra explícita por coleção; a última, com if false, garante que qualquer coleção nova nasce fechada.

Um prompt de revisão antes de publicar

Revê a segurança desta app com Firebase e não mudes nada ainda. Responde com uma lista:
1. Regras do Firestore, Realtime Database e Storage que permitam acesso a qualquer pessoa, com data de modo de teste ou com request.auth != null como única condição.
2. Regras de escrita que não validem os campos, em especial role, isAdmin, plan ou credits.
3. Chaves que não sejam a configuração do Firebase presentes no código do navegador, com ficheiro e linha.
4. Cloud Functions HTTP que não verifiquem o token do utilizador, e funções que leiam segredos do código em vez do Secret Manager.
5. Se o App Check está ativado e se a chave de API está restringida por domínio.
6. Cabeçalhos de segurança no firebase.json e ficheiros na pasta pública que não devam estar lá.
Para cada ponto, propõe a regra ou a alteração exata e espera pela minha confirmação.

Verifica o resultado de fora

O teu projectId está no bundle, por isso qualquer pessoa pode fazer isto. A API REST do Firestore sem token:

curl -s "https://firestore.googleapis.com/v1/projects/O_TEU_PROJETO/databases/(default)/documents/users" | head -c 400
curl -sI https://oteudominio.com | grep -iE "strict-transport|x-frame|x-content-type"

O correto é um erro de permissões na primeira (se devolver documentos, a coleção está aberta) e os cabeçalhos na segunda. Repete a primeira com cada coleção e com o Storage. O Scanaris faz estas verificações e cerca de quarenta mais em 30 segundos: deteta a configuração do Firebase no teu bundle, testa as coleções habituais sem autenticação, procura outras chaves no JavaScript, revê cabeçalhos, CORS, cookies e ficheiros expostos, e dá-te um fix prompt por cada achado para colar no Lovable, no Bolt ou no Cursor. Se a tua app usa Supabase em vez de Firebase, o guia do Supabase é o equivalente.

Perguntas frequentes

Tenho de esconder a apiKey do Firebase?

Não. É pública por desenho e identifica o projeto. O que protege os dados são as regras e o App Check. O que convém é restringi-la aos teus domínios no Google Cloud.

As Cloud Functions são privadas?

Uma função HTTP é um URL público. Verifica o token do utilizador dentro da função ou usa funções callable com App Check. As funções que reagem a eventos (um documento criado, um ficheiro carregado) não têm URL e são de facto internas.

Como testo as regras sem partir a app?

Com o simulador da consola (separador Regras) para testar leituras concretas, e com o emulador local para testes automáticos. Muda as regras com a app aberta noutro separador e verifica que o que deve funcionar continua a funcionar.

Verificações relacionadas

A tua app Firebase passa nestas verificações?

Analisa-a grátis e recebe um fix prompt por cada problema que encontrarmos.

Analisar o meu site grátis