Prejsť na obsah

How to enable RLS in Supabase: čo vráti po každom kroku

Zobraziť ako MarkdownOtvoriť v ClaudeOtvoriť v ChatGPTOtvoriť v Perplexity

Otázka sa tiež skopíruje. Ak sa chat otvorí prázdny, vložte ju.

TL;DR

RLS v Supabase zapnete jedným príkazom na tabuľku, alter table public.todos enable row level security;, alebo voľbou „Enable RLS“ v dashboarde. Tabuľky vytvorené v SQL editore alebo migráciou ho v predvolenom stave nemajú. Hneď po zapnutí tabuľka skôr stíchne, než aby kričala. V mojom lokálnom teste dostal verejný kľúč aj dvaja prihlásení používatelia pri select, update a delete 200 [] a zlyhal len insert, s 42501. Tajný kľúč stále videl všetky 3 riadky. Obyčajný pohľad (view) nad tabuľkou stále vydal všetky 3 riadky verejnému kľúču. Od 30. októbra 2026 navyše nová tabuľka potrebuje grant, než sa k nej niečo dostane, takže zapnite RLS a napíšte politiky v tej istej migrácii ako grant.

Prevádzkujem bezplatnú Kontrolu zabezpečenia Supabase a „RLS disabled“ je nález, ktorý je vysvetlený najhoršie. Väčšina návodov hovorí, že po zapnutí RLS sa „tabuľka stane neprístupnou“. Pri čítaní to platí, pri zápisoch to klame. Preto som postavil jednu tabuľku na lokálnom Supabase stacku a po každom z krokov nižšie jej posielal všetky druhy požiadaviek: ako verejný kľúč, ako dvaja prihlásení používatelia a ako tajný kľúč.

Čo je RLS v Supabase?

RLS (row-level security) je funkcia Postgresu, ktorá filtruje riadky podľa požiadavky. Supabase mení každú požiadavku z supabase-js na dopyt do databázy, ktorý beží ako rola: anon pre verejný kľúč (anon, publishable), authenticated pre prihláseného používateľa. Pri zapnutom RLS Postgres kontroluje vaše politiky pre každý riadok a vracia, mení alebo maže len tie riadky, ktoré politika povolí. Pri vypnutom RLS sa každá rola s grantom na tabuľku dostane ku všetkým riadkom.

Tajný kľúč (service role) je iný. Jeho rola má BYPASSRLS, takže sa naň RLS nikdy nevzťahuje. Preto patrí len na server. Rozdiel medzi oboma kľúčmi je v článku Supabase anon key vs service role key: čo ktorý otvorí.

Ako zapnúť RLS v Supabase?

Tromi spôsobmi, podľa toho, ako tabuľka vznikla:

  • Pri vytváraní tabuľky v Table Editore nechajte zaškrtnuté „Enable Row Level Security (RLS)“. V zdrojovom kóde dashboardu je označené „Recommended“ a pri vypnutí sa zobrazí varovanie, že tabuľka bude verejne čitateľná a zapisovateľná.
  • Pri existujúcej tabuľke sprievodca zabezpečením API od Supabase hovorí: otvorte Database, potom Policies a pri tabuľke zvoľte „Enable RLS“.
  • V SQL, v SQL editore alebo v migrácii:
alter table public.todos enable row level security;

Sprievodca Supabase výslovne uvádza, že tabuľky vytvorené v dashboarde majú RLS zapnuté v predvolenom stave a tabuľky vytvorené v SQL editore alebo iným nástrojom nie. Ak schému tvoríte migráciami alebo AI nástrojom, skontrolujte každú tabuľku.

Čo sa stane hneď po zapnutí RLS?

Nič nehlási chybu okrem insertu. Vytvoril som public.todos so stĺpcom vlastníka (user_id uuid default auth.uid()), udelil jej práva rolám API tak, ako to robili staršie projekty, a pridal tri riadky: dva patriace používateľovi A a jeden používateľovi B. Potom som zapol RLS bez akejkoľvek politiky:

Požiadavka Verejný kľúč Používateľ A Používateľ B Tajný kľúč
Select 200, 0 riadkov 200, 0 riadkov 200, 0 riadkov 200, 3 riadky
Insert vlastného riadku 401, chyba 42501 403, chyba 42501 403, chyba 42501 201, riadok vložený
Update riadku 200, 0 riadkov 200, 0 riadkov 200, 0 riadkov 200, 1 riadok
Delete riadku 200, 0 riadkov 200, 0 riadkov 200, 0 riadkov 200, 1 riadok

Chyba insertu znie new row violates row-level security policy. Update a delete odpovedia 200 s prázdnym poľom, takže aplikácia, ktorá nekontroluje vrátené riadky, hlási „uložené“, aj keď sa nič neuložilo. Po zapnutí RLS si zápisy načítajte späť, alebo si vyžiadajte počet cez Prefer: count=exact.

Pred RLS, s rovnakými grantmi, mohol verejný kľúč prečítať všetky 3 riadky, vkladať a meniť alebo mazať ľubovoľný riadok. Používateľ A mohol upraviť a zmazať riadok používateľa B a svoje riadky odovzdať používateľovi B.

Ako tabuľku znova sprevádzkovať?

Napíšte politiku pre každú operáciu. Obvyklá sada pre vlastné riadky:

create policy "own select" on public.todos for select to authenticated
  using ((select auth.uid()) = user_id);
create policy "own insert" on public.todos for insert to authenticated
  with check ((select auth.uid()) = user_id);
create policy "own update" on public.todos for update to authenticated
  using ((select auth.uid()) = user_id) with check ((select auth.uid()) = user_id);
create policy "own delete" on public.todos for delete to authenticated
  using ((select auth.uid()) = user_id);

S týmito politikami videl používateľ A svoje 2 riadky a používateľ B svoj 1. Verejný kľúč stále videl 0. Keď sa A pokúsil vložiť riadok patriaci B alebo presunúť vlastný riadok k B, odpoveď bola 403, 42501. Toto odmietnutie pochádza z with check pri update. Keď sa A pokúsil zmeniť alebo zmazať riadok používateľa B, odpoveď bola 200, 0 rows. Ďalšie vzory (verejné profily, tímy, MFA) sú v článku Supabase RLS policy: príklady otestované cez API.

Jeden detail z tajného kľúča: riadok, ktorý vložil, dostal user_id = null, pretože auth.uid() za týmto kľúčom nemá žiadneho používateľa. RLS sa preskočilo, ale predvolená hodnota neurobila to, čo naznačuje názov stĺpca.

Čo čítal verejný kľúč v jednotlivých krokoch?

Riadky prečítané verejným kľúčom, z 3. Jedna tabuľka Supabase s 3 riadkami, po každom kroku. Nová tabuľka, bez grantu, RLS off (chyba 42501): 0; Grant pridaný, RLS off: 3; RLS on, bez politiky: 0; RLS on, vlastné politiky: 0; Obyčajný view nad tabuľkou: 3; View so security_invoker: 0.
Obrázok 1. Lokálny Supabase stack (CLI 2.109.1, Postgres 17.6), 28. októbra 2026.

Dva kroky vyzradia všetko: grant bez RLS a obyčajný view nad tabuľkou so správnymi politikami. Ďalšie dve sekcie vysvetľujú oba.

Potrebujete RLS aj po zmene grantov z 30. októbra?

Áno. Od 30. októbra 2026 Supabase už nedáva novým tabuľkám v public automatické granty pre role API, pri nových aj existujúcich projektoch. Môj lokálny stack sa už tak správa. Čerstvo vytvorená tabuľka s vypnutým RLS odpovedala 42501 všetkým rolám, vrátane tajného kľúča, takže nič neuniklo. Podrobnosti sú v článku Supabase 30. októbra: zmena grantov a čo prestane fungovať.

Grant sa však vráti, hneď ako aplikácia tabuľku potrebuje, a od tej chvíle je RLS jediné, čo stojí medzi verejným kľúčom a všetkými riadkami. Preto dajte všetko do jednej migrácie, v tomto poradí:

create table public.todos (...);
alter table public.todos enable row level security;
create policy "own select" on public.todos ...;
grant select, insert, update, delete on table public.todos to authenticated;

Udeľte grant len rolám, ktoré tabuľku potrebujú. Keď som roli anon odobral všetko, select verejného kľúča sa zmenil z 200 [] na 401, 42501. Grant je prvý zámok, RLS druhý.

Prečo view stále prepúšťa riadky?

Pretože view beží s právami svojho vlastníka, a v Supabase je to postgres, ktorý RLS obchádza. Pri platných politikách pre vlastné riadky na todos vrátil obyčajný create view public.todos_view as select * from public.todos všetky 3 riadky verejnému kľúču aj používateľovi B.

Po vytvorení znova s with (security_invoker = true) vrátil rovnaký view verejnému kľúču 0 riadkov, A 2 a B 1, presne ako tabuľka:

create view public.todos_view with (security_invoker = true) as
  select * from public.todos;

Advisor Supabase označuje obyčajný druh ako security_definer_view; čo to znamená a ako to opraviť, je v poznámke o Supabase view security definer.

Ako zapnúť RLS na každej novej tabuľke automaticky?

Event triggerom. Sprievodca event triggermi od Supabase uvádza funkciu rls_auto_enable() a trigger ensure_rls, ktorý beží po create table, create table as a select into v public. Nainštaloval som ho tak, ako je zverejnený, a dostal:

  • Tabuľka vytvorená potom príkazom create table mala RLS zapnuté bez akéhokoľvek alter. Verejný kľúč dostal 200 [] pri select a 401 pri insert.
  • Tabuľka vytvorená príkazom create table as select tiež mala RLS zapnuté.
  • Tabuľka vytvorená pred triggerom zostala vypnutá. Trigger nepôsobí spätne.

Bez triggera mala druhá tabuľka vytvorená vedľa chránenej RLS vypnuté, a hneď ako dostala grant, verejný kľúč ju voľne čítal aj zapisoval. Pokrýva tiež len public; ostatné vystavené schémy potrebujú vlastný riadok vo funkcii.

Pomáha FORCE ROW LEVEL SECURITY?

Nie pri rolách, o ktoré by ste sa báli. alter table ... force row level security spôsobí, že sa RLS uplatní aj na vlastníka tabuľky. V Supabase majú postgres aj service_role BYPASSRLS, takže vlastník po force stále napočítal 3 riadky, tajný kľúč stále videl všetko a view vlastnený postgres stále prepúšťal. Zmenilo to len rolu vlastníka, ktorú som vytvoril bez BYPASSRLS: 2 riadky pred, 0 po.

Ako skontrolovať vlastný projekt?

  • V SQL editore vypíšte tabuľky v public s vypnutým RLS:
select c.relname as table_name
from pg_class c
join pg_namespace n on n.oid = c.relnamespace
where n.nspname = 'public'
  and c.relkind in ('r', 'p')
  and not c.relrowsecurity
order by 1;
  • Advisor v dashboarde hlási to isté ako rls_disabled_in_public; čo tá chyba znamená, je v poznámke o RLS disabled in public.
  • Bezplatná Kontrola zabezpečenia Supabase číta váš projekt len na čítanie a vypíše tabuľky s vypnutým RLS, ku ktorým API dosiahne, views obchádzajúce RLS a politiky, ktoré povoľujú všetkým, ku každému s opravným SQL.
  • Skener nemôže vedieť, ktoré riadky komu patria. Aby ste to dokázali, pošlite požiadavky ako dvaja používatelia, ako je uvedené vyššie. Celá metóda pre aplikáciu s rolami je v článku Ako testovať Supabase RLS: 30 z 87 oprávnení nerobilo nič.

Ako som testoval

  • Supabase CLI 2.109.1 na notebooku: Postgres 17.6, PostgREST 14.14, Auth 2.192.0. Dvaja používatelia prihlásení heslom a lokálne publishable a secret kľúče.
  • Jedna tabuľka, public.todos, pred každou požiadavkou znovu naplnená rovnakými 3 riadkami. Každý krok bol aplikovaný ako SQL a každá požiadavka išla cez REST API, so zaznamenaným stavovým kódom a telom.
  • Granty pre kroky 2 až 5 boli pridané ručne, aby zodpovedali projektu vytvorenému pred 30. októbrom 2026.

Limity. Jeden lokálny stack, vymyslené dáta, 28. októbra 2026. Kroky v dashboarde sú citované z dokumentácie Supabase, nie preklikané. Tabuľky vytvorené vlastnou rolou dashboardu môžu mať iné predvolené granty. To som netestoval, rovnako ako Storage, Realtime alebo GraphQL.

Nie ste si istí, že sú vaše tabuľky zamknuté?

Rád sa pozriem na schému spolu s vami. Bez ponuky.

Ozvite sa

© 2026 Denys Zaichenko. Pôvodný článok: https://madsalt.tech/sk/blog/how-to-enable-rls-in-supabase/