Supabase RLS: o guia de segurança que faltou antes de você lançar
12 de outubro de 2026 · ~8 min de leitura
O Supabase expõe o seu Postgres direto para o navegador. Isso é o que o deixa rápido — e também o que o torna perigoso: a sua Row Level Security (RLS) não é "mais uma camada", ela é a autorização da sua API. Se ela estiver frouxa, qualquer pessoa com a sua chave anônima (que é pública por design) lê e escreve no seu banco. Abaixo, os 7 erros que mais vemos, com o SQL errado e o certo.
anon key está no bundle do seu front-end — qualquer um a copia do DevTools. Com ela, dá para falar com o PostgREST do Supabase direto, sem passar pelo seu app. A RLS é a única coisa decidindo o que essa pessoa pode ver. Não é teoria: já houve vários vazamentos públicos de apps Supabase com RLS desligada.
1. RLS simplesmente desligada na tabela
O erro número um, e o mais grave. Criar a tabela no editor e esquecer de ligar a RLS deixa ela totalmente aberta pela chave anônima — leitura e escrita de tudo.
-- ✅ Ligue a RLS em TODA tabela com dado real alter table public.orders enable row level security; -- Ache as tabelas sem RLS: select tablename from pg_tables where schemaname='public' and rowsecurity=false;
Ligar a RLS sem criar política nenhuma nega tudo por padrão (seguro). O perigo é a tabela que nunca teve a RLS ligada.
2. A política using (true)
RLS ligada, mas com uma política que libera geral. Parece protegido no painel, mas não protege nada.
-- ❌ Todo mundo lê tudo create policy "ler" on orders for select using (true); -- ✅ Só o dono lê create policy "dono lê" on orders for select using (auth.uid() = user_id);
3. Proteger o SELECT e esquecer o INSERT/UPDATE/DELETE
Políticas em Postgres são por operação. É comum caprichar na leitura e deixar a escrita aberta — aí o usuário insere linha em nome de outro, ou atualiza o que não é dele. Leitura usa using; escrita precisa de with check.
-- ✅ Insert: a linha nova TEM que ser do usuário create policy "dono insere" on orders for insert with check (auth.uid() = user_id); -- ✅ Update: valida a linha antiga (using) E a nova (with check) create policy "dono atualiza" on orders for update using (auth.uid() = user_id) with check (auth.uid() = user_id);
4. Confiar num user_id que o cliente manda
Se a sua política de insert não amarra a linha ao auth.uid(), o cliente escolhe o user_id que quiser no insert e grava dado como se fosse outra pessoa. O with check (auth.uid() = user_id) acima fecha isso: a identidade vem do token, não do corpo da requisição.
5. A chave service_role no front-end
A service_role ignora a RLS por completo — é a chave de administrador. Se ela vazar para o navegador (num NEXT_PUBLIC_…, por exemplo), toda a sua RLS deixa de existir. Ela só pode viver no servidor (Edge Function, rota de API), nunca em código que vai para o cliente.
-- ❌ no front NEXT_PUBLIC_SUPABASE_SERVICE_ROLE_KEY=... -- ✅ no front NEXT_PUBLIC_SUPABASE_ANON_KEY=... (anon, protegida por RLS)
6. Funções e views que furam a RLS
Uma função security definer roda com os privilégios de quem a criou e ignora a RLS do chamador — útil, mas um tiro no pé se exposta sem cuidado. Views, por padrão, também podiam expor dados por cima da RLS. Prefira security invoker quando possível e revise o que está exposto no schema public.
create function minha_fn() returns setof orders
language sql security invoker as $$ select * from orders $$;
7. Esquecer o Storage (e o Realtime)
Buckets do Supabase Storage têm as próprias políticas de RLS. Travar as tabelas e deixar o bucket público expõe os arquivos dos usuários a quem tiver a URL. Cada bucket privado precisa de política amarrada ao dono.
-- ✅ cada usuário só mexe na própria pasta no Storage create policy "arquivos do dono" on storage.objects for all using ( bucket_id='uploads' and (storage.foldername(name))[1] = auth.uid()::text );
anon key num script e tente ler a linha de outro usuário. Se vier dado, a política está frouxa — é exatamente um caso de isolamento multi-cliente. No Firebase a lógica é a mesma pelo outro lado — veja os 7 erros de Firebase Security Rules.
Não quer caçar política por política?
O SAAS SHIELD revisa seu repositório com Supabase ou Firebase e devolve cada falha de acesso com local, evidência e correção.
Solicitar auditoria →