O Firebase é o backend favorito de muitas apps feitas com IA: o Lovable, o Bolt ou o Cursor ligam-no em minutos e tens autenticação, base de dados e ficheiros sem montar um servidor. O problema é que o seu modelo de segurança é o contrário do de um backend tradicional. Aqui o navegador fala diretamente com a base de dados, por isso não há um servidor a filtrar pedidos: as regras de segurança são a tua única barreira, e uma regra mal escrita deixa todos os dados à vista. Este guia percorre os dez erros que mais se repetem, com a regra errada e a certa em cada caso, e termina com como o verificares tu mesmo.
1. Regras em modo de teste, ou o que vem a seguir
Ao criar uma base de dados, o Firebase oferece-te o "modo de teste": tudo aberto durante trinta dias. A regra tem este aspeto:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if request.time < timestamp.date(2026, 11, 3);
}
}
}
Até essa data, qualquer pessoa com o teu projectId (que está no código do navegador) pode ler e escrever toda a base de dados. E o pior vem depois: ao expirar, a app deixa de funcionar, o programador procura uma solução rápida e substitui a data por if true. Agora o buraco é permanente. A solução é escrever regras por coleção desde o primeiro dia, baseadas em quem é o utilizador e de quem é o documento.
2. allow read: if true em dados de utilizadores
Há coleções que podem ser públicas (um catálogo de produtos, os posts de um blog). Mas allow read: if true em users, orders ou messages significa que qualquer pessoa pode descarregar a lista completa. A forma correta de proteger documentos por utilizador:
match /users/{userId} {
allow read, write: if request.auth != null
&& request.auth.uid == userId;
}
Cada utilizador lê e escreve só o seu documento. Para dados partilhados entre vários (uma equipa, um projeto) guarda a lista de membros no documento e verifica-a na regra.
3. Confundir "autenticado" com "autorizado"
A regra allow read: if request.auth != null parece segura e é o erro mais comum. Diz: qualquer utilizador com sessão pode ler. Mas registar-se na tua app é grátis e demora dez segundos, por isso na prática é o mesmo que aberto. Autenticado responde a quem és; autorizado, a o que podes ver. As regras têm de responder à segunda.
4. Dados sensíveis em documentos legíveis
Um perfil público com nome e avatar é razoável. O mesmo documento com email, telefone, morada e um token de acesso, não. Se outros utilizadores têm de poder ver parte do perfil, separa o público do privado em dois documentos ou numa subcoleção private com regras mais estritas. O que não está num documento legível não pode fugir.
5. Pensar que a configuração do Firebase é um segredo
O objeto com apiKey, authDomain e projectId vai para o navegador por desenho: identifica o teu projeto, não autoriza nada. Vê-lo no código-fonte não é uma falha, e não é o que há a esconder. O que deves fazer com essa chave é restringi-la na consola do Google Cloud aos domínios do teu site (restrição por referenciador HTTP) e ativar o App Check, que exige que os pedidos venham da tua app real e não de um script.
6. Outras chaves são mesmo secretas
O erro grave é outro: junto à configuração do Firebase, o bundle leva a chave secreta do Stripe, a da OpenAI ou a de um serviço de email porque "assim era mais fácil". Essas chaves dão acesso a dinheiro e a contas de terceiros. O lugar delas é uma Cloud Function com os segredos em variáveis de ambiente, e o navegador chama a função, nunca o serviço diretamente. O detalhe está em segredos que a tua app deixa fugir no navegador.
7. Storage sem regras próprias
O Cloud Storage tem as suas próprias regras e costuma ser esquecido. Com allow read, write: if request.auth != null qualquer utilizador registado pode ler os ficheiros dos outros, carregar o que quiser para qualquer caminho e encher a tua quota. Uma regra razoável limita o caminho ao utilizador e valida tamanho e tipo:
match /users/{userId}/{fileName} {
allow read: if request.auth != null && request.auth.uid == userId;
allow write: if request.auth != null
&& request.auth.uid == userId
&& request.resource.size < 5 * 1024 * 1024
&& request.resource.contentType.matches('image/.*');
}
8. Realtime Database aberta
Se usas a base de dados em tempo real em vez do Firestore, o equivalente é ".read": true na raiz. As regras são outra linguagem, mas a lógica é a mesma: nada aberto na raiz, e permissões por ramo com auth.uid.
9. Escrever sem validar
Permitir escrita ao dono do documento não chega se não validas o que escreve. Um utilizador pode acrescentar isAdmin: true ou plan: "pro" ao seu próprio perfil a partir da consola do navegador. Valida os campos com request.resource.data: que chaves existem, de que tipo são e que os campos sensíveis não mudam.
allow update: if request.auth.uid == userId
&& !request.resource.data.diff(resource.data).affectedKeys()
.hasAny(['isAdmin', 'plan', 'credits']);
10. Esquecer a fatura
O Firebase cobra por leitura. Uma regra que permite list sem limite numa coleção grande deixa que um script leia milhões de documentos e te gere uma fatura inesperada. Limita as consultas a partir das regras (request.query.limit <= 100), ativa o App Check e põe alertas de orçamento no Google Cloud.
Como verificar tu mesmo
- Simulador de regras. Na consola do Firebase, separador Regras, há um simulador onde testas uma leitura como utilizador anónimo ou com um UID concreto. Tenta ler
userssem sessão: deve ser negado. - Emulador com testes. O emulador local permite escrever testes automáticos de regras. É a única forma de não as partires ao mudá-las.
- De fora, sem token. A API REST do Firestore responde a qualquer pessoa:
curl "https://firestore.googleapis.com/v1/projects/O_TEU_PROJETO/databases/(default)/documents/users"
Se devolver documentos, essa coleção está aberta. Se devolver um erro de permissões, a regra funciona. Repete com cada coleção que tenhas.
O Scanaris revê o teu Firebase de fora
O Scanaris deteta a configuração do Firebase no teu bundle, verifica se as coleções habituais respondem sem autenticação, procura outras chaves que não deviam estar no navegador e revê cabeçalhos, CORS e ficheiros expostos. Por cada achado dá-te um fix prompt com a regra ou a alteração exata para colar no Lovable, no Bolt ou no Cursor. São verificações só de leitura sobre o que já é público. A lista completa de riscos está no guia de segurança para Firebase, e antes de lançar convém rever a checklist de segurança.
Perguntas frequentes
É um problema a minha apiKey do Firebase estar no código?
Não por si só: identifica o projeto, não dá permissões. O que protege os dados são as regras. Ainda assim, restringe a chave aos teus domínios e ativa o App Check para evitar abusos.
O que faço se as minhas regras estão abertas neste momento?
Fecha primeiro: põe regras por coleção com request.auth.uid mesmo que alguma função deixe de funcionar, e corrige a app depois. Depois revê nos registos de utilização se houve leituras anómalas e, se havia dados pessoais expostos, pondera se tens de o notificar.
Posso pedir à minha IA que escreva as regras?
Sim, e costuma fazê-lo bem se lhe deres a estrutura das tuas coleções e quem deve ver o quê. Mas testa-as no simulador antes de publicar: uma IA também escreve if request.auth != null a acreditar que é seguro.