Início › Blog › Supabase RLS

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.

Entenda a ameaça: a 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 );
Como auditar a sua RLS hoje: rode a query do item 1 para achar tabelas sem RLS; abra o Security Advisor no painel do Supabase (ele lista tabelas expostas); e teste de verdade — use a 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 →