TIPS 24 · PORTA

A tua base de dados responde a toda a gente?

O teste de dois minutos para perceber se a base de dados da tua app responde também a quem não fez login, e o prompt que a fecha. Só na tua app.

O que é e porque importa

Muitas apps feitas com o Claude Code usam um backend já pronto, como o Supabase ou o Firebase. É prático: a app fala diretamente com a base de dados, a partir do browser ou do telemóvel, sem um servidor teu pelo meio.

Para isso, a app leva consigo duas coisas: o endereço do projeto e uma chave pública. Qualquer pessoa que abra a tua app as pode ver, basta olhar para os pedidos no browser. E está certo assim: essa chave foi feita para estar ali. Não é uma palavra-passe, diz apenas «este pedido vem da minha app».

A questão é o que está atrás da porta. Quem decide quem pode ler o quê não é a chave: são as regras na base de dados. No Supabase chamam-se Row Level Security (segurança ao nível da linha), no Firebase regras de segurança. Em palavras simples: para cada tabela escreves quem pode ler, acrescentar, alterar e apagar que linhas. Por exemplo: «cada utilizador vê só as suas encomendas».

Se essas regras faltam, ou estão escritas de forma demasiado larga, a chave pública abre tudo. Quem copia o endereço e a chave do browser pode ler as tabelas: emails, nomes, mensagens, tudo o que lá puseste. Às vezes até alterá-las. Não é preciso ser hacker: basta uma linha no terminal.

O Claude cria as tabelas e a app funciona, porque a ti, com sessão iniciada, os dados chegam. Que cheguem também a quem não tem conta nenhuma, usando a app não vês. Só vês se o testares.

Antes de tudo: só na tua app

Este teste fazes no teu projeto, com os teus dados ou com utilizadores de teste. Nunca em apps ou bases de dados de outros, nem sequer «só para ver»: entrar num sistema sem autorização pode ser crime, em Itália como em muitos outros países. Se achas que a app de outra pessoa está aberta, não a testes: escreve a quem a gere.

1. O teste, em dois minutos

Três partes: a primeira encontra a chave, a segunda vê o que vê quem não fez login, a terceira se um utilizador lê os dados de outro. Descrevo-as no Supabase; para o Firebase, vê mais abaixo.

a. Encontra a chave

  1. Abre a tua app no browser, sem fazer login.
  2. Botão direito > Inspecionar > separador Rede (Network), depois recarrega a página.
  3. Procura os pedidos à base de dados. No Supabase são endereços que terminam em .supabase.co.
  4. Clica num pedido: aí vês o endereço do projeto e a chave pública (publishable ou anon).

Se não encontrares pedidos à base de dados, vai a uma página que carregue dados e volta a ver.

b. Tenta ler sem login

Sem login, abre um terminal e corre esta linha. Põe o teu projeto, a tua chave pública e o nome de uma das tuas tabelas:

A linha
curl "https://O-TEU-PROJETO.supabase.co/rest/v1/NOME_TABELA?select=*" -H "apikey: CHAVE_PUBLICA"

Se voltarem linhas de utilizadores, a porta está aberta. Se voltar uma lista vazia, [], ou um erro de permissão, essa tabela não responde a quem passa. Dois cuidados: confirma que a tabela tem mesmo dados, senão uma lista vazia não te diz nada. E repete para cada tabela, não só para uma.

c. Testa como utilizador A

Cria dois utilizadores de teste, A e B, e faz cada um guardar alguma coisa: um perfil, uma nota, uma encomenda. Depois entra como A e copia o token de acesso dele: encontra-lo no separador Rede, no cabeçalho Authorization dos pedidos feitos depois do login. A seguir corre:

A linha
curl "https://O-TEU-PROJETO.supabase.co/rest/v1/NOME_TABELA?select=*" -H "apikey: CHAVE_PUBLICA" -H "Authorization: Bearer TOKEN_DE_A"

Os dois cabeçalhos têm funções diferentes. A chave pública vai sempre em apikey. Authorization: Bearer leva só o token de acesso de um utilizador que fez login, nunca a chave pública e nunca a secreta. Por isso a primeira linha só tem apikey: ali não há utilizador nenhum.

Se entre as linhas estiverem as de B, A lê B. É o buraco mais fácil de não notar: a porta está fechada a quem não fez login, mas lá dentro cada um vê tudo. Trata o token de A como uma palavra-passe: com ele és A. Usa-o só para o teste e não o coles em lado nenhum.

Se não o queres fazer à mão

Pede ao Claude, dentro do teu projeto. Ele faz os pedidos por ti:

O prompt
Faz tu o teste: com a chave pública e sem login tenta ler cada tabela; depois, com dois utilizadores de teste, verifica se A vê os dados de B. Diz-me tabela a tabela o que está aberto. Não alteres nada.

Se o Claude Code te pedir autorização para correr um comando, lê o que vai fazer antes de dizer que sim. «Não alteres nada» serve precisamente para isto: o teste lê, não escreve.

2. O prompt que resolve

Quando sabes o que está aberto, fecha. Este é o prompt que eu uso:

O prompt
Cada utilizador vê só as suas linhas. Ativa a Row Level Security em cada tabela e escreve as regras: leitura, inserção, alteração e eliminação só nas linhas do utilizador com sessão iniciada. As tabelas mesmo públicas (ex. um catálogo) só de leitura. Verifica também as vistas, as funções RPC e os buckets do Storage. Lista-me tudo com a regra que puseste, depois repete o teste e mostra-me que A já não vê B.

As palavras são escolhidas. «Leitura, inserção, alteração e eliminação» porque no Supabase as regras escrevem-se para cada operação: se fechares só a leitura, alguém ainda pode escrever ou apagar. «As vistas, as funções RPC e os buckets do Storage» porque os dados não saem só das tabelas. No Supabase uma vista, por omissão, salta as regras das tabelas que lê; uma função pode ser escrita de forma a saltá-las; os ficheiros carregados têm regras próprias. E «repete o teste» porque uma regra verifica-se experimentando-a, não lendo-a.

3. Duas coisas a saber

Mais vale uma porta fechada

No Supabase, com a Row Level Security ativa e nenhuma regra escrita, com a chave pública não passa nada: mais vale uma porta fechada do que aberta. Depois abres só o que é preciso. Se depois da correção um ecrã deixar de carregar dados, não desligues a segurança: falta uma regra. Pede ao Claude para acrescentar essa, e mais nada.

As duas chaves

  • A chave pública (publishable, ou anon nos projetos mais antigos) pode estar na app e no browser. Sozinha abre só o que as regras permitem.
  • A chave secreta (secret ou service_role) salta todas as regras: só no servidor, nunca na app, nunca no GitHub.

Se a chave secreta foi parar à app ou a um repositório, considera-a queimada. Cria uma nova no painel do Supabase, põe-na no lugar da antiga onde for preciso, e só depois apaga ou desativa a antiga. Tirá-la do código não chega: fica no histórico e com quem já a viu.

O prompt
Procura no código da app, e em tudo o que vai parar ao browser ou à app publicada, se está lá a chave secreta do Supabase (secret ou service_role). Verifica também o histórico do git. Diz-me onde a encontras. Não alteres nada.

Se usas o Firebase

A mesma ideia, lá chamam-se regras de segurança. Também no Firebase a chave da app não é um segredo: serve para identificar o projeto. O que protege os dados são as regras.

A regra a procurar é a que deixa passar toda a gente, tipo allow read, write: if true. A documentação do Firebase diz para nunca a usar em produção. No lugar dela são precisas regras que verifiquem quem fez login e de quem é o documento.

O prompt
Lê as regras de segurança do Firebase do meu projeto. Diz-me que coleções pode ler ou escrever quem não fez login, e se um utilizador consegue ler os documentos de outro. Depois propõe-me regras em que cada utilizador vê e altera só os seus dados. Não publiques nada até eu te dizer.

Os erros mais comuns

  • Fazer o teste numa só tabela. Cada tabela tem as suas regras: testa-as todas.
  • Fechar só a leitura. Escreve as regras também para inserção, alteração e eliminação.
  • Fechar as tabelas e esquecer vistas, funções e ficheiros. Verifica-os também, com o mesmo teste.
  • Uma regra que deixa ler tudo a qualquer pessoa com login feito. O controlo certo é sobre quem é dono da linha, não sobre ter sessão iniciada.
  • Desligar a segurança quando um ecrã deixa de funcionar. Acrescenta a regra que falta em vez de voltar a abrir tudo.
  • Pôr a chave secreta na app ou no repositório. Usa-a só no servidor e, se saiu cá para fora, substitui-a.

Checklist

  • Fiz o teste sem login em cada tabela.
  • Com dois utilizadores de teste, A não vê os dados de B.
  • Cada tabela tem regras para leitura, inserção, alteração e eliminação.
  • Verifiquei também vistas, funções RPC e buckets do Storage.
  • As tabelas públicas são só de leitura.
  • A chave secreta está só no servidor.
  • Repeti o teste depois da correção.

Perguntas frequentes

Posso fazer este teste na app de outra pessoa, por curiosidade?

Não. Só na tua app. Ler dados de um sistema sem autorização pode ser crime, mesmo que a porta esteja aberta. Se suspeitas de um problema, avisa quem gere a app.

Depois da correção a app deixou de carregar alguns dados. O que fiz mal?

Provavelmente nada: a porta agora está fechada e falta uma regra para esse caso. Diz ao Claude que ecrã não carrega e pede-lhe a regra mais apertada que chegue, depois repete o teste com A e B.

Tenho de o repetir de vez em quando?

Sempre que acrescentares uma tabela ou mudares quem pode ver o quê. As regras valem tabela a tabela, e uma tabela nova pode nascer sem nenhuma.

← Todos os guias