---
title: "Supabase security definer view: miks see jätab RLS vahele"
description: "Miks Supabase'i view tagastab read, mida RLS tema tabelis varjab, mida tähendab Advisori hoiatus security_definer_view ja milline seade selle parandab."
url: "https://madsalt.tech/et/notes/supabase-security-definer-view/"
author: "Denys Zaichenko"
author_url: "https://madsalt.tech/et/about/"
language: "et"
published: 2026-11-02
---

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

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](https://madsalt.tech/et/tools/supabase-security-check/) 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](https://supabase.com/docs/guides/database/postgres/row-level-security) ü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.](https://madsalt.tech/charts/et/supabase-security-definer-view.svg)

*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:

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

Uue view puhul pange see määratlusse:

```sql
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:

```sql
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](https://madsalt.tech/et/blog/lovable-app-security-checklist/) ja kuidas poliitikaid ennast tõestada, on artiklis [kuidas Supabase'i RLS-i testida](https://madsalt.tech/et/blog/how-to-test-supabase-rls/). Poliitika, mis otsib tiimid abifunktsiooni kaudu ilma rekursioonita, on artiklis [Supabase RLS policy näited, testitud API kaudu](https://madsalt.tech/et/blog/supabase-rls-policy-examples/). `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](https://madsalt.tech/et/notes/supabase-function-search-path-mutable/).
