RLS no Supabase: o que é e como configurar sem vazar dados
Row Level Security é a única coisa entre a chave pública do seu app e os dados de todos os usuários. Como ligar, como escrever políticas, os erros mais comuns e como testar de verdade.
O que é Row Level Security
Row Level Security (RLS) é um recurso do PostgreSQL que aplica um filtro automático a cada consulta: antes de devolver ou alterar uma linha, o banco confere se ela passa na política da tabela. É como se cada select ganhasse um where que o usuário não consegue tirar.
No Supabase, o RLS não é opcional na prática. O app envia para o navegador a URL do projeto e a chave pública (chamada anon ou publishable), e com elas qualquer pessoa consegue chamar a API do banco diretamente. Sem RLS, essa chamada devolve a tabela inteira.
Como ligar
Tabelas criadas pelo editor visual do painel costumam vir com RLS ligado. Tabelas criadas por SQL, por migração ou por ferramentas de IA podem não vir. Ligue em toda tabela do schema public:
alter table public.pedidos enable row level security;service_role). É o estado seguro: a partir dele, você abre só o necessário.Como escrever as políticas
Cada política vale para uma operação (select, insert, update, delete) e um papel (anon para visitantes, authenticated para logados). A cláusula using filtra as linhas que podem ser lidas ou alteradas; with check valida as linhas que estão sendo gravadas.
O caso mais comum: cada usuário vê e altera só os próprios registros.
-- Ler só os próprios pedidos
create policy "pedidos: ler os próprios"
on public.pedidos for select
to authenticated
using ((select auth.uid()) = user_id);
-- Criar pedidos só em nome próprio
create policy "pedidos: criar os próprios"
on public.pedidos for insert
to authenticated
with check ((select auth.uid()) = user_id);
-- Alterar só os próprios, sem poder passar o pedido para outra pessoa
create policy "pedidos: alterar os próprios"
on public.pedidos for update
to authenticated
using ((select auth.uid()) = user_id)
with check ((select auth.uid()) = user_id);Envolver auth.uid() em (select …) faz o banco calcular o valor uma vez por consulta, não uma vez por linha, o que importa em tabelas grandes.
Os erros mais comuns
using (true)para "fazer funcionar". É o mesmo que não ter RLS. Aparece muito em código gerado por IA depois de um erro de permissão.- Update sem
with check. O usuário altera o próprio registro e troca ouser_idpara o de outra pessoa. - Confiar em
user_metadata. O usuário consegue alterar os próprios metadados. Papel de administrador nunca vem dali: use uma tabela de papéis protegida ouapp_metadata, que só o servidor altera. - Views que ignoram as políticas. Por padrão, uma view roda com as permissões de quem a criou. No PostgreSQL 15 ou superior, crie com
with (security_invoker = true). - Funções
security definerchamáveis pela API, que rodam com privilégio total e precisam conferir o usuário por conta própria. - Storage esquecido. Arquivos ficam em
storage.objects, que tem as próprias políticas. Bucket público é público para todos. - Chave
service_roleno front-end. Ela ignora o RLS inteiro. Veja chave exposta no frontend.
Como testar de verdade
Política escrita não é política testada. O teste que vale é o que um atacante faria: chamar a API direto, sem a tela.
1. Sem login, com a chave pública. Toda tabela que não é pública deve voltar vazia.
curl "https://SEU-PROJETO.supabase.co/rest/v1/pedidos?select=*" \
-H "apikey: SUA_CHAVE_PUBLICA"2. Logado como o usuário A, lendo dados do usuário B. Faça login com dois usuários de teste, copie o token de acesso do A (na aba Network, cabeçalho Authorization) e peça um registro do B pelo ID.
curl "https://SEU-PROJETO.supabase.co/rest/v1/pedidos?id=eq.ID_DO_PEDIDO_DE_B" \
-H "apikey: SUA_CHAVE_PUBLICA" \
-H "Authorization: Bearer TOKEN_DO_USUARIO_A"3. Escrita. Repita com POST e PATCH, tentando gravar um registro com o user_id de outra pessoa. A resposta certa é erro.
4. Automatize. Transforme esses testes em testes do seu repositório, para que uma migração futura que desligue o RLS quebre o build em vez de ir para produção. O Security Advisor do painel do Supabase também aponta tabelas sem RLS e deve ser revisado a cada mudança de schema.
Checklist de RLS
- RLS ligado em toda tabela do schema
public. - Nenhuma política
using (true)em tabela com dado pessoal. - Toda política de
updateeinsertcomwith check. - Papel de administrador fora de
user_metadata. - Views com
security_invokere funçõessecurity definerrevisadas. - Políticas do Storage revisadas e buckets privados por padrão.
- Testes sem login e com dois usuários, no repositório.