---
title: "Supabase security definer view: kodėl jis apeina RLS"
description: "Kodėl Supabase view grąžina eilutes, kurias RLS slepia jo lentelėje, ką reiškia Advisor įspėjimas security_definer_view ir koks vienas nustatymas tai ištaiso."
url: "https://madsalt.tech/lt/notes/supabase-security-definer-view/"
author: "Denys Zaichenko"
author_url: "https://madsalt.tech/lt/about/"
language: "lt"
published: 2026-11-02
---

# Supabase security definer view: kodėl jis apeina RLS

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

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

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

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

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

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

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](https://madsalt.tech/lt/blog/lovable-app-security-checklist/), o kaip įrodyti pačias politikas, rasite straipsnyje [kaip testuoju Supabase RLS](https://madsalt.tech/lt/blog/how-to-test-supabase-rls/). Politika, kuri komandų ieško per pagalbinę funkciją, be rekursijos, pateikta straipsnyje [Supabase RLS policy: pavyzdžiai, išbandyti per API](https://madsalt.tech/lt/blog/supabase-rls-policy-examples/). 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](https://madsalt.tech/lt/notes/supabase-function-search-path-mutable/).
