O que supabase faz?
Princípios Fundamentais
1. O Supabase muda com frequência — verifique o changelog e a documentação atual antes de implementar. Não confie nos dados de treinamento para recursos do Supabase. Assinaturas de funções, configurações de config.toml e convenções de API mudam entre versões.
Primeiro, busque https://supabase.com/changelog.md (um índice de resumo leve — não uma busca pesada), verifique se há tags breaking-change relevantes para sua tarefa e siga a página vinculada para as que se aplicarem. Em seguida, consulte o tópico relevante usando os métodos de acesso à documentação abaixo.
2. Verifique seu trabalho. Após implementar qualquer correção, execute uma consulta de teste para confirmar que a alteração funciona. Uma correção sem verificação está incompleta.
3. Recupere-se de erros, não repita. Se uma abordagem falhar após 2 a 3 tentativas, pare e reconsidere. Tente um método diferente, verifique a documentação, inspecione o erro com mais cuidado e revise os logs relevantes quando disponíveis. Os problemas do Supabase nem sempre são resolvidos repetindo o mesmo comando, e a resposta nem sempre está nos logs, mas muitas vezes vale a pena verificar os logs antes de prosseguir.
4. Expondo tabelas à API de Dados: Dependendo das configurações da API de Dados do usuário, tabelas recém-criadas podem não ser automaticamente expostas através da API de Dados (REST). Se for esse o caso, os papéis anon e authenticated precisarão receber acesso explicitamente.
Observe que isso é separado do RLS, que controla quais linhas são visíveis quando uma tabela está acessível, não se a tabela está acessível.
Quando um usuário relatar que uma tabela criada via SQL está inesperadamente inacessível, verifique as configurações da API de Dados e se os papéis receberam acesso por meio de GRANT SQL explícito. Ao conceder acesso público (anon/authenticated), sempre habilite o RLS também. Veja Expondo uma Tabela à API de Dados para o fluxo de trabalho completo de configuração.
5. RLS em esquemas expostos.
Habilite o RLS em todas as tabelas de qualquer esquema exposto, o que inclui public por padrão. Isso é crítico no Supabase porque tabelas em esquemas expostos podem ser acessíveis através da API de Dados quando os papéis anon/authenticated têm acesso (veja Expondo uma Tabela à API de Dados). Para esquemas privados, prefira RLS como defesa em profundidade. Após habilitar o RLS, crie políticas que correspondam ao modelo de acesso real, em vez de padronizar todas as tabelas com o mesmo padrão auth.uid().
6. Lista de verificação de segurança. Ao trabalhar em qualquer tarefa do Supabase que envolva autenticação, RLS, views, storage ou dados do usuário, execute esta lista de verificação. Estas são armadilhas de segurança específicas do Supabase que criam vulnerabilidades silenciosamente:
-
Segurança de autenticação e sessão
- Nunca use as claims
user_metadataem decisões de autorização baseadas em JWT. No Supabase,raw_user_meta_dataé editável pelo usuário e pode aparecer emauth.jwt(), portanto, não é seguro para políticas de RLS ou qualquer outra lógica de autorização. Armazene dados de autorização emraw_app_meta_data/app_metadata. - Excluir um usuário não invalida tokens de acesso existentes. Faça logout ou revogue as sessões primeiro, mantenha a expiração do JWT curta para aplicativos sensíveis e, para garantias estritas, valide
session_idem relação aauth.sessionsem operações sensíveis. - Se você usa
app_metadataouauth.jwt()para autorização, lembre-se de que as claims do JWT nem sempre estão atualizadas até que o token do usuário seja renovado.
- Nunca use as claims
-
Exposição de chave de API e cliente
- Nunca exponha a chave
service_roleou secreta em clientes públicos. Prefira chaves publicáveis para código de frontend. Chavesanonlegadas são apenas para compatibilidade. No Next.js, qualquer variável de ambienteNEXT_PUBLIC_é enviada para o navegador.
- Nunca exponha a chave
-
RLS, views e código de banco de dados privilegiado
- Views ignoram o RLS por padrão. No Postgres 15 e superior, use
CREATE VIEW ... WITH (security_invoker = true). Em versões antigas do Postgres, proteja suas views revogando o acesso dos papéisanoneauthenticated, ou colocando-as em um esquema não exposto. - UPDATE requer uma política SELECT. No RLS do Postgres, um UPDATE precisa primeiro SELECT a linha. Sem uma política SELECT, updates retornam silenciosamente 0 linhas — sem erro, apenas nenhuma alteração.
auth.role()está obsoleto — use a cláusulaTO. O Supabase descontinuouauth.role()em favor de especificar o papel alvo diretamente na política comTO authenticatedouTO anon. Além da descontinuação,auth.role() = 'authenticated'quebra silenciosamente quando logins anônimos estão ativados, porque usuários anônimos carregam o papel Postgresauthenticatede passam na verificação independentemente de o usuário estar realmente logado.-- Obsoleto (não use) create policy "exemplo" on nome_da_tabela for select using ( auth.role() = 'authenticated' );TO authenticatedsozinho é autenticação sem autorização (BOLA / IDOR). UsarTO authenticatedapenas verifica o papel — não restringe quais linhas um usuário pode acessar. O padrão correto combinaTO authenticatedcom um predicado de propriedade emUSING:create policy "exemplo" on nome_da_tabela for select to authenticated using ( (select auth.uid()) = user_id );- Políticas UPDATE exigem tanto
USINGquantoWITH CHECK. SemWITH CHECK, um usuário pode reatribuir ouser_idde uma linha a outro usuário:create policy "exemplo" on nome_da_tabela for update to authenticated using ( (select auth.uid()) = user_id ) with check ( (select auth.uid()) = user_id ); - Funções
SECURITY DEFINERignoram o RLS. Uma funçãoSECURITY DEFINERé executada com os privilégios de seu criador — tipicamente um papel combypassrls(por exemplo,postgres). Nunca adicioneSECURITY DEFINERpara resolver um erro de permissão; isso remove silenciosamente o controle de acesso sem corrigir a causa subjacente. PrefiraSECURITY INVOKER. - Funções
SECURITY DEFINERempublicsão chamáveis por todos os papéis. O Postgres concedeEXECUTEaPUBLICpor padrão para cada nova função, portanto, qualquer funçãoSECURITY DEFINERempublicé um endpoint de API pública chamável poranoneauthenticated(que herdam dePUBLIC) sem qualquer concessão adicional. QuandoSECURITY DEFINERé genuinamente necessário (por exemplo, ignorando RLS em uma tabela de consulta interna), mantenha a função em um esquema não exposto, sempre inclua uma verificaçãoauth.uid()no corpo da função e executesupabase db advisorsapós fazer alterações.
- Views ignoram o RLS por padrão. No Postgres 15 e superior, use
-
Controle de acesso ao Storage
- Upsert no Storage requer INSERT + SELECT + UPDATE. Conceder apenas INSERT permite novos uploads, mas a substituição de arquivos (upsert) falha silenciosamente. Você precisa de todos os três.
-
Segurança de dependência e cadeia de suprimentos
- Sempre fixe as versões dos pacotes e confirme os arquivos de bloqueio (lockfiles) ao instalar pacotes Supabase (
supabase-js,@supabase/ssr,supabase-py, etc.). Veja o guia de segurança npm para a lista de verificação completa.
- Sempre fixe as versões dos pacotes e confirme os arquivos de bloqueio (lockfiles) ao instalar pacotes Supabase (
Para qualquer preocupação de segurança não abordada acima, busque o índice de segurança de produtos do Supabase: https://supabase.com/docs/guides/security/product-security.md