[{"data":1,"prerenderedAt":425},["ShallowReactive",2],{"blog-pt-supabase-rls-on-but-table-still-public":3},{"id":4,"title":5,"body":6,"category":387,"cover":388,"coverAlt":388,"description":389,"draft":390,"extension":391,"faq":392,"image":405,"keywords":406,"meta":412,"navigation":413,"ogTitle":414,"path":415,"published":416,"seo":417,"stem":418,"tldr":419,"updated":423,"__hash__":424},"blog_pt\u002Fblog\u002Fsupabase-rls-on-but-table-still-public.md","O Supabase Row Level Security está ligado. A tabela continua pública.",{"type":7,"value":8,"toc":376},"minimark",[9,13,21,26,29,32,35,39,42,45,56,77,80,89,93,104,195,201,204,212,216,223,230,233,239,249,253,256,259,298,301,306,310,313,316,327,330,334,363],[10,11,12],"p",{},"Você ligou o Row Level Security porque alguma coisa mandou: o advisor dentro do\nSupabase, um checklist, o resultado de um scan, alguém num Discord. A chave está\nverde no seu painel agora. E mesmo assim estão te dizendo que a sua tabela\ncontinua legível por estranhos.",[10,14,15,16,20],{},"Aqui está a parte que guia após guia conta errado: ",[17,18,19],"strong",{},"a chave não protege nada.","\nEla decide que as suas regras vão ser conferidas. As regras são outra coisa,\nvocê tem que escrever, e a regra mais rápida de escrever (a que faz um app\nquebrado voltar a funcionar) deixa todo mundo entrar.",[22,23,25],"h2",{"id":24},"o-row-level-security-está-ligado-no-supabase-como-a-tabela-continua-pública","O Row Level Security está ligado no Supabase. Como a tabela continua pública?",[10,27,28],{},"Porque ligar e decidir quem entra são dois passos diferentes, e só o primeiro é\numa chave.",[10,30,31],{},"Pense na chave como colocar alguém na porta. Acioná-la não decide quem passa.\nDecide que agora alguém confere uma lista. Suas políticas são essa lista. Uma\nlista vazia barra todo mundo; uma lista que diz \"todos\" não barra ninguém. As\nduas coisas são Row Level Security ligado, e o seu painel mostra o mesmo verde\nnos dois casos.",[10,33,34],{},"É por isso que a configuração sozinha responde muito pouco, e por isso o nosso\nscanner nunca pergunta ao Supabase se ela está ativa. Ele pergunta para a\ntabela. Manda o pedido que um estranho mandaria, com a chave pública que viaja\ndentro do seu app, e vê se volta uma resposta. Ele pede uma contagem em vez das\nlinhas, então descobre que a porta abriu sem ler nada do que está atrás.",[22,36,38],{"id":37},"a-política-que-consertou-o-seu-app-provavelmente-é-o-problema","A política que consertou o seu app provavelmente é o problema",[10,40,41],{},"No momento em que você liga o Row Level Security, o seu app para de mostrar\ndados, e o que você fez logo depois para ele voltar a funcionar é justamente o\nque merece uma olhada.",[10,43,44],{},"Essa sequência é completamente normal, e é onde a coisa desanda. Com a\nconfiguração ligada e nenhuma política escrita, o Postgres (o banco de dados em\nque o Supabase roda) recusa todos os pedidos por padrão, então suas listas\nvoltam vazias e suas telas ficam em branco. Alguma\ncoisa precisa entrar na lista. Se você pediu para o Cursor ou o Lovable\nconsertar, ou colou o primeiro trecho que fez o erro sumir, o que você tem agora\nprovavelmente é assim:",[46,47,52],"pre",{"className":48,"code":50,"language":51},[49],"language-text","CREATE POLICY \"Enable read access for all users\"\n  ON public.profiles\n  FOR SELECT\n  USING (true);\n","text",[53,54,50],"code",{"__ignoreMap":55},"",[10,57,58,61,62,65,66,69,70,73,74,76],{},[53,59,60],{},"USING (true)"," é a condição que uma linha precisa cumprir antes de o banco\nentregar. Toda linha cumpre ",[53,63,64],{},"true",". Tem um segundo detalhe ali dentro que é\nfácil passar batido: sem a cláusula ",[53,67,68],{},"TO",", uma política vale para ",[53,71,72],{},"public",", e\n",[53,75,72],{}," cobre visitantes logados e estranhos completos do mesmo jeito.",[10,78,79],{},"Aí o app volta a funcionar, nada dá erro, e a tabela está exatamente tão legível\nquanto estava antes de você começar.",[10,81,82,83,88],{},"Isso conserta a leitura, e só a leitura. Se o seu app também salva nessa tabela,\na próxima coisa que você encontra é\n",[84,85,87],"a",{"href":86},"\u002Fblog\u002Fnew-row-violates-row-level-security-policy","new row violates row-level security policy",", que é a mesma configuração\nrecusando uma escrita, e nenhuma policy de leitura resolve.",[22,90,92],{"id":91},"os-quatro-estados-em-que-uma-tabela-pode-estar","Os quatro estados em que uma tabela pode estar",[10,94,95,96,99,100,103],{},"Dois deles são seguros e dois não, e a chave não te diz quais. \"Chave\npublicável\" abaixo é a que tem lugar no seu app: ",[53,97,98],{},"sb_publishable_…"," nos projetos\nnovos do Supabase, ",[53,101,102],{},"anon"," nos antigos.",[105,106,107,126],"table",{},[108,109,110],"thead",{},[111,112,113,117,120,123],"tr",{},[114,115,116],"th",{},"Row Level Security",[114,118,119],{},"A política",[114,121,122],{},"Seu app",[114,124,125],{},"Um estranho com a sua chave publicável do Supabase",[127,128,129,148,165,179],"tbody",{},[111,130,131,135,138,141],{},[132,133,134],"td",{},"Desligado",[132,136,137],{},"tanto faz, nenhuma é lida",[132,139,140],{},"Funciona",[132,142,143],{},[144,145,147],"key-verdict",{"type":146},"danger","Lê todas as linhas",[111,149,150,153,156,159],{},[132,151,152],{},"Ligado",[132,154,155],{},"nenhuma escrita",[132,157,158],{},"Quebrado",[132,160,161],{},[144,162,164],{"type":163},"safe","Não lê nada",[111,166,167,169,173,175],{},[132,168,152],{},[132,170,171],{},[53,172,60],{},[132,174,140],{},[132,176,177],{},[144,178,147],{"type":146},[111,180,181,183,188,190],{},[132,182,152],{},[132,184,185],{},[53,186,187],{},"USING (auth.uid() = user_id)",[132,189,140],{},[132,191,192],{},[144,193,194],{"type":163},"Lê só as dele",[196,197],"diagram",{"alt":198,"caption":199,"src":200},"Quatro tabelas lado a lado. Na primeira a chave está desligada e as seis linhas são legíveis. Na segunda a chave está ligada com a caixa de política vazia e nenhuma linha é legível. Na terceira a chave está ligada com uma política que diz true, e as seis linhas voltam a ser legíveis. Na quarta a chave está ligada com uma política que compara o dono da linha, e só duas linhas são legíveis.","A marca embaixo de cada coluna não segue a chave de cima. Duas delas estão ligadas e uma dessas entrega tudo.","\u002Fblog\u002Fsupabase-rls-on-but-table-still-public\u002Frls-four-states-1600x760.png",[10,202,203],{},"As duas colunas do meio são o par que pega as pessoas. Mesma configuração, mesmo\nselo verde, resultados opostos, e a diferença é uma palavra dentro de uma regra\nque quase ninguém abre.",[10,205,206,207,211],{},"Se você preferir não ler cada política por conta própria, o nosso scan gratuito\nfaz ao seu banco no ar a mesma pergunta que um estranho faria e diz quais\ntabelas responderam. Leva uns 20 segundos e não precisa de conta:\n",[84,208,210],{"href":209},"\u002F#scan","escaneie seu app",".",[22,213,215],{"id":214},"authenticated-não-é-a-mesma-coisa-que-seu","\"Authenticated\" não é a mesma coisa que \"seu\"",[10,217,218,219,222],{},"Uma política que permite ",[53,220,221],{},"authenticated"," permite todo mundo que tem conta, o que\n(se o seu app tem um cadastro aberto) é todo mundo disposto a preencher.",[10,224,225,226,229],{},"Essa é a versão mais sutil do mesmo erro, e ela sobrevive a muita revisão porque\nparece caprichada. ",[53,227,228],{},"TO authenticated USING (true)"," se lê como uma restrição, e é\numa: exclui quem nunca se cadastrou. O que ela não faz é impedir um cliente seu\nde ler as linhas de outro cliente, que costuma ser o que você queria dizer com\n\"privado\".",[10,231,232],{},"A regra que faz isso nomeia de quem é a linha:",[46,234,237],{"className":235,"code":236,"language":51},[49],"CREATE POLICY \"Users read their own rows\"\n  ON public.orders\n  FOR SELECT\n  TO authenticated\n  USING (auth.uid() = user_id);\n",[53,238,236],{"__ignoreMap":55},[10,240,241,244,245,248],{},[53,242,243],{},"auth.uid()"," é quem está perguntando. ",[53,246,247],{},"user_id"," é a coluna na linha que diz de\nquem ela é. A linha volta quando os dois batem, e fica onde está quando não\nbatem.",[22,250,252],{"id":251},"como-conferir-suas-próprias-tabelas-em-dois-minutos","Como conferir suas próprias tabelas em dois minutos",[10,254,255],{},"Abra o Supabase, vá em Authentication → Policies e leia a expressão dentro de\ncada política em vez do selo do lado de cada tabela.",[10,257,258],{},"Três coisas para procurar:",[260,261,262,271,279],"ul",{},[263,264,265,270],"li",{},[17,266,267,268,211],{},"Uma política cuja condição é ",[53,269,64],{}," Decida, tabela por tabela, se você\nficaria bem com aqueles dados numa página aberta. Para uma lista de artigos\npublicados, sim. Para qualquer coisa com uma pessoa dentro, não.",[263,272,273,278],{},[17,274,275,276,211],{},"Uma política sem cláusula ",[53,277,68],{}," Ela vale para todo mundo, logado ou não,\nmesmo quando o resto da regra parece bem específico.",[263,280,281,284,285,288,289,292,293,297],{},[17,282,283],{},"Uma tabela com a configuração ligada, nenhuma política, e um app que mesmo\nassim funciona."," Essa combinação significa que alguma coisa está chegando aos\nseus dados por outro caminho, e a explicação de sempre é uma chave\nsecreta (",[53,286,287],{},"sb_secret_…",", ou ",[53,290,291],{},"service_role"," num projeto antigo), que ignora\ntodas as políticas que você escreveu.\n",[84,294,296],{"href":295},"\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend","Quais chaves de API são seguras no frontend","\nmostra como distinguir essa da segura.",[10,299,300],{},"A outra conferida a que as pessoas recorrem é abrir o app numa janela anônima\nsem entrar na conta. Vale fazer, mas saiba o que ela prova. O seu app decide o\nque desenhar. O seu banco decide o que entregar. São decisões diferentes, e um\nestranho que pula as suas telas recebe a segunda.",[196,302],{"alt":303,"caption":304,"src":305},"Dois caminhos até as mesmas linhas. Passando pelas telas do app, voltam duas de seis linhas. Indo direto ao endereço do banco de dados, voltam as seis.","As telas do seu app não são a cerca. A mesma tabela pode mostrar duas linhas pelo seu app e entregar as seis para um pedido que nunca o abriu.","\u002Fblog\u002Fsupabase-rls-on-but-table-still-public\u002Fapp-view-vs-database-1600x620.png",[22,307,309],{"id":308},"como-isso-parece-enquanto-está-acontecendo-com-você","Como isso parece enquanto está acontecendo com você",[10,311,312],{},"Não parece nada. É esse o formato desse problema, e é por isso que ele fica\nparado por meses.",[10,314,315],{},"Nenhum erro aparece no seu builder. Nada fica mais lento, nenhuma tela quebra,\nnenhum e-mail chega. Seu app se comporta exatamente como no dia em que você\nlançou, porque do lado dele nada mudou: ele sempre teve permissão de ler aquelas\nlinhas. O que mudou é que todo mundo também tem, usando a chave que viaja no\ncódigo que o seu site manda para cada visitante.",[10,317,318,319,322,323,326],{},"Quando aparece, aparece de lado. Uma cliente pergunta como alguém soube de uma\ncoisa que só o seu app sabia. Uma lista de endereços que você nunca publicou\nsurge em algum lugar. E se a regra generosa cobre escrita além de leitura,\n",[53,320,321],{},"FOR ALL"," em vez de ",[53,324,325],{},"FOR SELECT",", aí qualquer pessoa também pode alterar e\napagar linhas, que é a versão que as pessoas descobrem como uma tabela de\nrepente vazia.",[10,328,329],{},"Regras também escorregam. Uma migração, uma mudança de schema, mais um conserto\nde madrugada que precisava que os dados carregassem: qualquer um desses pode\nafrouxar uma política sem avisar, e por isso aqui vale uma segunda olhada mais\npara frente, e não só uma agora. Ficar de olho nisso é parte do que o Reeve Care\nfaz, embora um lembrete na sua agenda cumpra o mesmo papel.",[22,331,333],{"id":332},"o-que-fazer-esta-semana","O que fazer esta semana",[335,336,337],"key-takeaways",{},[260,338,339,342,345,354,360],{},[263,340,341],{},"Abra Authentication → Policies no Supabase e leia a condição de cada política, tabela por tabela. O selo na tabela não é a resposta.",[263,343,344],{},"Para cada tabela com pessoas dentro (usuários, perfis, pedidos, mensagens), confira se a regra nomeia o dono da linha em vez de permitir todo mundo.",[263,346,347,348,350,351,353],{},"Troque qualquer ",[53,349,60],{}," nessas tabelas por uma regra que compare ",[53,352,243],{}," com a coluna do dono, e confirme depois que o seu app ainda carrega.",[263,355,356,357,359],{},"Acrescente a cláusula ",[53,358,68],{}," que você queria. Uma política sem ela vale para estranhos igual vale para visitantes logados.",[263,361,362],{},"Se uma tabela tem a configuração ligada, nenhuma política, e o seu app mostra os dados dela mesmo assim, descubra o que está passando por cima antes de mexer em qualquer outra coisa.",[10,364,365,366,370,371,375],{},"Comece pela tabela que mais te constrangeria se fosse uma página aberta, e\nresolva essa hoje. O ",[84,367,369],{"href":368},"\u002Fchecklist","checklist de segurança de 10 minutos"," cobre\nisso junto com o resto do que vale olhar num app recém-lançado, e o\n",[84,372,374],{"href":373},"\u002Fis-your-supabase-app-safe","guia de segurança do Supabase"," passa pelo que mais\ncostuma ficar aberto.",{"title":55,"searchDepth":377,"depth":377,"links":378},3,[379,381,382,383,384,385,386],{"id":24,"depth":380,"text":25},2,{"id":37,"depth":380,"text":38},{"id":91,"depth":380,"text":92},{"id":214,"depth":380,"text":215},{"id":251,"depth":380,"text":252},{"id":308,"depth":380,"text":309},{"id":332,"depth":380,"text":333},"Noções de segurança",null,"Ligar o Supabase Row Level Security não protege uma tabela. Quem protege são as políticas, e a que consertou o seu app pode deixar qualquer um entrar.",false,"md",[393,396,399,402],{"q":394,"a":395},"Liguei o Row Level Security e meu app parou de mostrar dados. Quebrei alguma coisa?","Não, isso é a configuração funcionando. Com o Row Level Security ligado e nenhuma política escrita, o Postgres (o banco de dados por baixo do Supabase) recusa todos os pedidos por padrão, inclusive os do seu próprio app. A solução é adicionar uma política que descreva quem deve ver quais linhas. O erro a evitar é adicionar uma que permita todo mundo, porque é essa que faz o app voltar a funcionar e deixa a tabela aberta.",{"q":397,"a":398},"USING (true) alguma vez é a política certa?","Sim, para dados que são realmente públicos. Uma tabela de posts publicados, um catálogo de produtos, uma lista de lugares num mapa: eles existem para serem lidos por qualquer pessoa, e uma política que permite isso está certa. Ela deixa de estar certa no momento em que a tabela tem pessoas dentro. Pergunte a si mesmo se você ficaria confortável publicando o conteúdo dessa tabela numa página aberta, e deixe a resposta decidir a política.",{"q":400,"a":401},"O Row Level Security me protege se a minha chave secreta vazou?","Não. Uma chave secreta do Supabase (sb_secret_ nos projetos novos, service_role nos antigos) ignora o Row Level Security por completo, e é para isso que ela serve. Todas as políticas que você escreveu são puladas, em todas as tabelas. Se essa chave está no seu frontend, suas políticas não estão fazendo nada por você, e girar a chave é o primeiro trabalho, antes de qualquer mexida nas regras.",{"q":403,"a":404},"Preciso de Row Level Security se meu app já tem tela de login?","Sim. Sua tela de login controla o seu app, e o seu app não é o único caminho até o seu banco de dados. O Supabase dá a cada projeto um endereço web que responde a pedidos diretamente, e a chave para falar com ele está no código que o seu app envia para cada visitante. As políticas são a parte que vale por qualquer porta que o pedido tenha entrado.","\u002Fblog\u002Fsupabase-rls-on-but-table-still-public\u002Fcard-800x500.png",[407,408,409,410,411],"supabase rls","row level security politica","tabela supabase publica","rls nao funciona","seguranca supabase",{},true,"O Supabase RLS está ligado. Sua tabela continua pública.","\u002Fblog\u002Fsupabase-rls-on-but-table-still-public","2026-08-10",{"title":5,"description":389},"blog\u002Fsupabase-rls-on-but-table-still-public",[420,421,422],"No Supabase, a chave e as regras são duas coisas diferentes. Ligado sem regra não deixa ninguém passar; ligado com a regra errada não segura ninguém.","A regra que faz um app quebrado voltar a funcionar costuma ser a que permite qualquer pedido, de qualquer pessoa.","Leia a política, não o botão. Uma única palavra decide se um estranho consegue ler a sua tabela.","2026-08-12","CqG9DwSIr5bNB4XbCskAPT-gmcl_jT0k6qcozCFq9Cw",1787826050910]