Liigu sisu juurde

Supabase security definer view: miks see jätab RLS vahele

Supabase

Vaata MarkdowninaAva rakenduses ClaudeAva rakenduses ChatGPTAva rakenduses Perplexity

Küsimus kopeeritakse ka. Kui vestlus avaneb tühjana, kleepige see sisse.

Lühidalt

Postgresi view töötab oma omaniku õigustega, kui see pole loodud valikuga security_invoker = true. Supabase’is on omanik tavaliselt postgres, mis jätab RLS-i vahele, nii et kaitstud tabeli peale ehitatud view tagastab ridu, mida tabel ise varjab. Minu kohalikul pinul sai publishable key tabelist 0 rida ja tavalisest view’st kõik 3 rida 3-st; kui security_invoker = true oli seatud, tagastas view samuti 0. Postgres 15 ja uuemas seadke see igale avaldatud skeemi view’le.

Minu tasuta Supabase’i turvakontrollil on reegel “Vaated, mis mööduvad RLS-ist” ja Supabase’i Security Advisor teatab sama asja kui security_definer_view. Seda on lihtne märkamata jätta, sest tabel, millest andmed lekivad, tundub kaitstud.

Miks Supabase’i view jätab RLS-i vahele?

View on salvestatud päring. Vaikimisi kontrollib Postgres selle sees olevate tabelite õigusi ja RLS-i view omaniku, mitte selle kutsuja nimel. Supabase’i RLS-i juhend ütleb selle otse: view’d jätavad RLS-i vaikimisi vahele, sest need luuakse tavaliselt kasutajaga postgres, ja kaitstud tabeli peale ehitatud view annab välja kõik read, mida selle poliitikad pidid kinni hoidma.

Data API serveerib view’sid nagu tabeleid. Kui view on avaldatud skeemis ja anon või authenticated saab sellest lugeda (select), loeb seda ka avalik võti.

Mida view minu testis tagastas?

Kohalikul Supabase’i pinul (CLI 2.109.1, Postgres 17.6, PostgREST 14.14) lõin tabeli orders kolme võltsklindiga, lülitasin RLS-i sisse ilma poliitikata ning tegin selle peale view order_summary, millel oli rollile anon select õigus. Seejärel päringisin mõlemat publishable key’ga:

Sama tabel, kolm viisi seda lugeda. Kohalik Supabase, RLS sees ilma poliitikata, publishable key. Tabel ise: Publishable key → orders, RLS sees → 0 rida; Tavaline view selle peal: Publishable key → order_summary view → 3 rida 3-st; View koos security_invoker'iga: Publishable key → security_invoker view → 0 rida.
Minu reproduktsioon kohalikul Supabase'i pinul, 23. oktoober 2026.
Päring publishable key’ga Tulemus
GET /rest/v1/orders (RLS sees, poliitikat pole) []
GET /rest/v1/order_summary (tavaline view) kõik 3 rida, nimede ja e-posti aadressidega
GET /rest/v1/order_summary pärast seadet security_invoker = true []

Sama tabel, sama võti. Tulemust muutis ainult view seadistus.

Kuidas seda parandada?

Postgres 15 ja uuemas, mida kõik praegused Supabase’i projektid kasutavad, pange view kontrollima RLS-i kutsuja nimel:

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

Uue view puhul pange see määratlusse:

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

Siis vajab kutsuja ka select õigust aluseks olevale tabelile ning ridu otsustavad tabeli poliitikad. Kui view peab koondama andmeid, mida kutsuja rida-realt ei näe, näiteks avalikku arvu, hoidke see avaldatud skeemist väljas ja serveerige seda hoopis kitsa tulemusega funktsiooni kaudu.

Skeemis public olevate view’de loetlemiseks, mis töötavad endiselt omaniku õigustega:

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);

Minu pinul, kus oli üks tavaline view ja kaks valikuga security_invoker = true, tagastas see ainult tavalise.

Materialiseeritud view’d ei toeta RLS-i üldse, seega märgib kontroll need API-s eraldi, reegli “Materialiseeritud vaated või välistabelid API-s” all. Mis veel poliitikatest mööda läheb, secret key’st SECURITY DEFINER funktsioonideni, on minu Lovable’i rakenduse turvanimekirjas ja kuidas poliitikaid ennast tõestada, on artiklis kuidas Supabase’i RLS-i testida. Poliitika, mis otsib tiimid abifunktsiooni kaudu ilma rekursioonita, on artiklis Supabase RLS policy näited, testitud API kaudu. SECURITY DEFINER funktsioon vajab veel ühte seadet, fikseeritud search_path’i; miks search_path = public minu testis ei piisanud, on märkuses Supabase “function search path mutable”: mida see tähendab.

© 2026 Denys Zaichenko. Algne artikkel: https://madsalt.tech/et/notes/supabase-security-definer-view/