Pereiti prie turinio

Supabase security definer view: kodėl jis apeina RLS

Supabase

Žiūrėti kaip MarkdownAtidaryti per ClaudeAtidaryti per ChatGPTAtidaryti per Perplexity

Klausimas taip pat nukopijuojamas. Jei pokalbis atsidaro tuščias, įklijuokite jį.

Trumpai

Postgres view veikia su savo savininko teisėmis, jei nesukurtas su security_invoker = true. Supabase savininkas paprastai yra postgres, kuris apeina RLS, todėl view virš apsaugotos lentelės grąžina eilutes, kurias pati lentelė slepia. Mano vietinėje aplinkoje viešasis raktas iš lentelės gavo 0 eilučių, o iš paprasto view virš jos visas 3 iš 3; su security_invoker = true view taip pat grąžino 0. Postgres 15 ir naujesnėje versijoje nustatykite tai kiekvienam view pateikiamoje schemoje.

Mano nemokamas Supabase saugos tikrintuvas turi taisyklę „Vaizdai, apeinantys RLS”, o Supabase Security Advisor tą patį praneša kaip security_definer_view. Tai lengva praleisti, nes lentelė, iš kurios nutekama, atrodo apsaugota.

Kodėl Supabase view apeina RLS?

View yra išsaugota užklausa. Pagal numatytuosius nustatymus Postgres lentelių teises ir RLS joje tikrina kaip view savininko, o ne kaip jį kviečiančiojo. Supabase RLS vadovas tai sako tiesiai: view pagal numatytuosius nustatymus apeina RLS, nes paprastai kuriami su naudotoju postgres, o view virš apsaugotos lentelės išduoda kiekvieną eilutę, kurią jos politikos turėjo sulaikyti.

Data API pateikia view kaip lenteles. Jei view yra pateikiamoje schemoje ir anon ar authenticated gali iš jo atlikti select, jį skaito ir viešasis raktas.

Ką view grąžino mano teste?

Vietiniame Supabase (CLI 2.109.1, Postgres 17.6, PostgREST 14.14) sukūriau lentelę orders su trimis išgalvotais klientais, įjungiau RLS be politikos ir virš jos sukūriau view order_summary su select teise rolei anon. Tada kviečiau abu su publishable key:

Ta pati lentelė, trys būdai ją skaityti. Vietinis Supabase, RLS įjungtas be politikos, publishable key. Pati lentelė: Publishable key → orders, RLS įjungtas → 0 eilučių; Paprastas view virš jos: Publishable key → order_summary view → 3 iš 3 eilučių; View su security_invoker: Publishable key → security_invoker view → 0 eilučių.
Mano atkartojimas vietiniame Supabase, 2026 m. spalio 23 d.
Užklausa su publishable key Rezultatas
GET /rest/v1/orders (RLS įjungtas, politikos nėra) []
GET /rest/v1/order_summary (paprastas view) visos 3 eilutės su vardais ir el. pašto adresais
GET /rest/v1/order_summary po security_invoker = true []

Ta pati lentelė, tas pats raktas. Rezultatą pakeitė tik view nustatymas.

Kaip tai ištaisyti?

Postgres 15 ir naujesnėje versijoje, kurią naudoja kiekvienas dabartinis Supabase projektas, priverskite view tikrinti RLS kaip kviečiantįjį:

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

Naujam view įrašykite tai apibrėžime:

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

Tada kviečiančiajam reikia ir select teisės į pagrindinę lentelę, o eilutes nusprendžia lentelės politikos. Jei view turi sumuoti duomenis, kurių kviečiantysis eilutė po eilutės nemato, pavyzdžiui, viešą skaičių, laikykite jį ne pateikiamoje schemoje ir pateikite per funkciją su siauru rezultatu.

Norėdami išvardyti public view, kurie vis dar veikia su savininko teisėmis:

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

Mano aplinkoje, kur buvo vienas paprastas view ir du su security_invoker = true, ji grąžino tik paprastąjį.

Materializuoti view RLS nepalaiko visai, todėl tikrintuvas juos API pažymi atskirai, taisykle „Medžiagintieji vaizdai ar išorinės lentelės API”. Kas dar eina pro politikas, nuo secret key iki SECURITY DEFINER funkcijų, aprašyta mano Lovable programos saugos sąraše, o kaip įrodyti pačias politikas, rasite straipsnyje kaip testuoju Supabase RLS. Politika, kuri komandų ieško per pagalbinę funkciją, be rekursijos, pateikta straipsnyje Supabase RLS policy: pavyzdžiai, išbandyti per API. Funkcijai su SECURITY DEFINER reikia dar vieno nustatymo, fiksuoto search_path; kodėl mano teste search_path = public nepakako, aprašyta pastaboje Supabase „function search path mutable“: ką tai reiškia.

© 2026 Denys Zaichenko. Originalus straipsnis: https://madsalt.tech/lt/notes/supabase-security-definer-view/