Supabase RLS: como verificar se os dados do seu app estão expostos
Por Guilherme Menezes. Última revisão: 6 de novembro de 2026.
Row Level Security (RLS) é o recurso do Postgres que decide quais linhas de uma tabela cada requisição pode ler ou alterar. Se o seu app usa Supabase e uma tabela não tem RLS, qualquer pessoa com a chave pública pode conseguir ler e alterar os dados dela. Para confirmar, verifique se o RLS está ativo em cada tabela e teste com dois usuários diferentes.
Por que isso é tão grave?
A chave pública do Supabase (a publishable, ou a antiga anon) foi feita para ficar no código do app, e qualquer pessoa consegue lê-la. A documentação do Supabase é clara: o que protege os dados são as regras de RLS, não o segredo dessa chave.
Sem RLS, uma tabela em um schema exposto pode ser lida e alterada por qualquer papel que tenha permissões sobre ela. Em projetos que ainda concedem permissões por padrão, as tabelas novas em public começam com todos os privilégios concedidos a anon, authenticated e service_role.
Como vejo se uma tabela tem RLS ativo?
No editor de SQL do Supabase, rode esta consulta:
select tablename, rowsecurity
from pg_tables
where schemaname = 'public';
Cada linha com rowsecurity em false é uma tabela sem RLS. Se ela guarda dados que não são públicos, é o primeiro problema a resolver.
Como ativo o RLS?
alter table public.faturas enable row level security;
Com o RLS ativo e sem regras, a API deixa de devolver dados com a chave pública. O seu app pode parecer quebrado até você criar as regras, então faça isso primeiro em um ambiente de teste.
Como escrevo uma regra que limita cada usuário aos próprios dados?
Esta regra deixa cada usuário ler só as próprias faturas. Ela assume que a coluna user_id guarda o dono:
create policy "Cada usuário lê as próprias faturas"
on public.faturas for select
to authenticated
using ( (select auth.uid()) = user_id );
auth.uid() devolve o id de quem faz a requisição, ou null se não houver sessão. Você precisa de uma regra para cada operação que o app usa: select, insert, update e delete.
Ter o RLS ativo basta?
Não. Estes são os erros que você deve procurar em seguida:
- Regras abertas a todos.
using ( true )paraanonexpõe todas as linhas a qualquer visitante. Só faz sentido para dados públicos. inserteupdatesemwith check. Sem essa condição, um usuário pode conseguir gravar linhas em nome de outro.- Chave secreta no navegador. A chave
secrete a antigaservice_roleignoram o RLS. Nunca podem estar no código que roda no navegador. Leia o guia sobre chaves expostas. - Código de servidor sem verificações. Uma função que usa a chave secreta ignora as regras, então ela mesma precisa confirmar quem pode fazer o quê.
Como testo de verdade?
Ler as regras não basta: teste.
- Crie dois usuários de teste, A e B, cada um com dados próprios.
- Com a sessão de A, tente ler, alterar e apagar os dados de B.
- Sem sessão, tente fazer o mesmo com a chave pública.
- Repita para cada tabela com dados privados.
Faça esses testes só no seu app e em um ambiente de teste. Se alguma requisição devolver ou alterar dados que não deveria, você tem uma falha a corrigir antes de lançar.