Prejsť na obsah

Supabase view security definer: prečo obchádza RLS

Supabase

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

View v Postgrese beží s právami svojho vlastníka, ak nie je vytvorené so security_invoker = true. V Supabase je vlastníkom zvyčajne postgres, ktorý RLS obchádza, takže view nad chránenou tabuľkou vracia riadky, ktoré tabuľka sama skrýva. Na mojom lokálnom stacku dostal verejný kľúč z tabuľky 0 riadkov a z obyčajného view nad ňou všetky 3 z 3; so security_invoker = true vrátilo view tiež 0. Na Postgrese 15 a novšom ho nastavte na každom view vo vystavenej schéme.

Môj bezplatný bezpečnostný checker pre Supabase má pravidlo „Pohľady, ktoré obchádzajú RLS“ a Security Advisor od Supabase hlási to isté ako security_definer_view. Ľahko sa prehliadne, pretože tabuľka, z ktorej dáta unikajú, vyzerá chránene.

Prečo view v Supabase obchádza RLS?

View je uložený dotaz. V predvolenom stave Postgres kontroluje oprávnenia a RLS na tabuľkách vo vnútri ako vlastník view, nie ako ten, kto ho volá. Sprievodca RLS od Supabase to hovorí priamo: views v predvolenom stave obchádzajú RLS, pretože sa zvyčajne vytvárajú používateľom postgres, a view nad chránenou tabuľkou vydá každý riadok, ktorý jej politiky mali zadržať.

Data API servíruje views rovnako ako tabuľky. Ak je view vo vystavenej schéme a anon alebo authenticated z neho smie vyberať, prečíta ho verejný kľúč.

Čo view vrátilo v mojom teste?

Na lokálnom stacku Supabase (CLI 2.109.1, Postgres 17.6, PostgREST 14.14) som vytvoril tabuľku orders s tromi fiktívnymi zákazníkmi, zapol RLS bez politiky a nad ňou view order_summary s grantom select pre anon. Potom som oboje zavolal s publishable key:

Rovnaká tabuľka, tri spôsoby čítania. Lokálny Supabase, RLS zapnuté bez politiky, publishable key. Samotná tabuľka: Publishable key → orders, RLS zapnuté → 0 riadkov; Obyčajné view nad ňou: Publishable key → view order_summary → 3 z 3 riadkov; View so security_invoker: Publishable key → view security_invoker → 0 riadkov.
Moja reprodukcia na lokálnom Supabase, 23. októbra 2026.
Požiadavka s publishable key Výsledok
GET /rest/v1/orders (RLS zapnuté, bez politiky) []
GET /rest/v1/order_summary (obyčajné view) všetky 3 riadky, s menami a e-mailami
GET /rest/v1/order_summary po security_invoker = true []

Rovnaká tabuľka, rovnaký kľúč. Odpoveď zmenilo iba nastavenie view.

Ako to opraviť?

Na Postgrese 15 a novšom, ktorý beží na každom aktuálnom projekte Supabase, nechajte view kontrolovať RLS ako volajúci:

alter view public.order_summary set (security_invoker = true);

Pri novom view ho uveďte v definícii:

create view public.order_summary
with (security_invoker = true)
as select customer, email, total from public.orders;

Volajúci potom potrebuje aj select na podkladovú tabuľku a o riadkoch rozhodujú politiky tabuľky. Ak view musí agregovať dáta, ktoré volajúci po riadkoch vidieť nesmie, napríklad verejný počet, nechajte ho mimo vystavenej schémy a ponúknite ho cez funkciu s úzkym výsledkom.

Zoznam views v public, ktoré stále bežia ako ich vlastník:

select c.relname as view
from pg_class c join pg_namespace n on n.oid = c.relnamespace
where n.nspname = 'public' and c.relkind = 'v'
  and not coalesce(
    (select bool_or(option = 'security_invoker=true' or option = 'security_invoker=on')
     from unnest(c.reloptions) as option), false);

Na mojom stacku, s jedným obyčajným view a dvoma so security_invoker = true, vrátil iba to obyčajné.

Materializované views RLS nepodporujú vôbec, preto ich checker hlási v API osobitne, pod „Materializované pohľady alebo cudzie tabuľky v API“. Čo ďalšie obchádza politiky, od secret key po funkcie SECURITY DEFINER, je v mojom checkliste bezpečnosti aplikácie z Lovable a ako dokázať, že samotné politiky fungujú, ukazuje ako testujem Supabase RLS. Politika, ktorá vyhľadáva tímy cez pomocnú funkciu, bez rekurzie, je v článku Supabase RLS policy: príklady otestované cez API. Funkcia so SECURITY DEFINER potrebuje ešte jedno nastavenie, pevný search_path; prečo v mojom teste search_path = public nestačilo, je v poznámke Supabase „function search path mutable“: čo to znamená.

© 2026 Denys Zaichenko. Pôvodný článok: https://madsalt.tech/sk/notes/supabase-security-definer-view/