Přejít na obsah

Supabase view security definer: proč obchází RLS

Supabase

Zobrazit jako MarkdownOtevřít v ClaudeOtevřít v ChatGPTOtevřít v Perplexity

Otázka se zkopíruje také. Pokud se chat otevře prázdný, vložte ji.

TL;DR

View v Postgresu běží s právy svého vlastníka, pokud není vytvořeno s security_invoker = true. V Supabase je vlastníkem obvykle postgres, který RLS obchází, takže view nad chráněnou tabulkou vrací řádky, které tabulka sama skrývá. Na mém lokálním stacku dostal veřejný klíč z tabulky 0 řádků a z obyčejného view nad ní všechny 3 ze 3; s security_invoker = true vrátilo view také 0. Na Postgresu 15 a novějším ho nastavte na každém view ve vystaveném schématu.

Můj bezplatný bezpečnostní checker pro Supabase má pravidlo „Pohledy, které obcházejí RLS“ a Security Advisor od Supabase hlásí totéž jako security_definer_view. Snadno se přehlédne, protože tabulka, ze které data unikají, vypadá chráněně.

Proč view v Supabase obchází RLS?

View je uložený dotaz. Ve výchozím stavu Postgres kontroluje oprávnění a RLS na tabulkách uvnitř něj jako vlastník view, ne jako ten, kdo ho volá. Průvodce RLS od Supabase to říká přímo: views ve výchozím stavu obcházejí RLS, protože se obvykle vytvářejí uživatelem postgres, a view nad chráněnou tabulkou vydá každý řádek, který její politiky měly zadržet.

Data API servíruje views stejně jako tabulky. Je-li view ve vystaveném schématu a anon nebo authenticated z něj smí vybírat, přečte ho veřejný klíč.

Co view vrátilo v mém testu?

Na lokálním stacku Supabase (CLI 2.109.1, Postgres 17.6, PostgREST 14.14) jsem vytvořil tabulku orders se třemi fiktivními zákazníky, zapnul RLS bez politiky a nad ní view order_summary s grantem select pro anon. Pak jsem obojí zavolal s publishable key:

Stejná tabulka, tři způsoby čtení. Lokální Supabase, RLS zapnuté bez politiky, publishable key. Samotná tabulka: Publishable key → orders, RLS zapnuté → 0 řádků; Obyčejné view nad ní: Publishable key → view order_summary → 3 ze 3 řádků; View se security_invoker: Publishable key → view security_invoker → 0 řádků.
Moje reprodukce na lokálním Supabase, 23. října 2026.
Požadavek s publishable key Výsledek
GET /rest/v1/orders (RLS zapnuté, bez politiky) []
GET /rest/v1/order_summary (obyčejné view) všechny 3 řádky, se jmény a e-maily
GET /rest/v1/order_summary po security_invoker = true []

Stejná tabulka, stejný klíč. Odpověď změnilo jen nastavení view.

Jak to opravit?

Na Postgresu 15 a novějším, který běží na každém aktuálním projektu Supabase, nechte view kontrolovat RLS jako volající:

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

U nového view ho uveďte v definici:

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

Volající pak potřebuje také select na podkladovou tabulku a o řádcích rozhodují politiky tabulky. Pokud view musí agregovat data, která volající po řádcích vidět nesmí, například veřejný počet, nechte ho mimo vystavené schéma a nabídněte ho přes funkci s úzkým výsledkem.

Seznam views v public, které stále běží jako jejich 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 mém stacku, s jedním obyčejným view a dvěma se security_invoker = true, vrátil jen to obyčejné.

Materializované views RLS nepodporují vůbec, proto je checker hlásí v API zvlášť, pod „Materializované pohledy nebo cizí tabulky v API“. Co dalšího obchází politiky, od secret key po funkce SECURITY DEFINER, je v mém checklistu zabezpečení aplikace z Lovable a jak dokázat, že samotné politiky fungují, ukazuje jak testuji Supabase RLS. Politika, která vyhledává týmy přes pomocnou funkci, bez rekurze, je v článku Supabase RLS policy: příklady otestované přes API. Funkce se SECURITY DEFINER potřebuje ještě jedno nastavení, pevný search_path; proč v mém testu search_path = public nestačilo, je v poznámce Supabase „function search path mutable“: co to znamená.

© 2026 Denys Zaichenko. Původní článek: https://madsalt.tech/cs/notes/supabase-security-definer-view/