---
title: "Supabase \"function search path mutable\": mida see tähendab"
description: "Mida tähendab hoiatus function_search_path_mutable, kes seda ära kasutada saab, miks search_path = public minu testis ei piisanud ja kuidas see parandada."
url: "https://madsalt.tech/et/notes/supabase-function-search-path-mutable/"
author: "Denys Zaichenko"
author_url: "https://madsalt.tech/et/about/"
language: "et"
published: 2026-11-01
---

# Supabase "function search path mutable": mida see tähendab

Lühidalt

Hoiatus tähendab, et funktsioonil pole fikseeritud `search_path`'i, mistõttu iga skeemita nimi selle sees, näiteks `admins`, otsitakse nii, nagu kutsuja sessioon ütleb. Minu kohalikus testis tagastas `SECURITY DEFINER` funktsioon `is_admin()` kasutajale, kes pole admin, väärtuse `true`, kui too oli loonud ajutise tabeli nimega `admins`, ja ka fikseeritud `search_path = public` ei peatanud seda. Aitas `set search_path = ''` koos igale tabelile kirjutatud kujuga `public.admins`.

Supabase'i Security Advisor loetleb selle lint'ina 0011, "Function Search Path Mutable", tase WARN, täpsustusega "Function `public.x` has a role mutable search_path". See märgib iga funktsiooni, millel seadet pole, ka `SECURITY INVOKER` funktsioonid, nii et paljude abifunktsioonidega projektis läheb nimekiri pikaks: üks avatud lähtekoodiga projekt [parandas neist 99 ühe migratsiooniga](https://github.com/bdougie/contributor.info/commit/3c73dda01df80faccb75278ec0f826a84e01a6d9).

## Mida tähendab "role mutable search_path"?

`search_path` on skeemide loend, kust Postgres otsib nime, mille ees pole skeemi. Funktsioon, millel pole oma seadet, kasutab kutsuja loendit. Supabase'i [lint'i leht](https://supabase.com/docs/guides/database/database-linter?lint=0011_function_search_path_mutable) soovitab selle seada tühjaks sõneks, mis sunnib iga viite funktsiooni sees kirjutama täieliku skeemanimega.

`SECURITY DEFINER` funktsiooni jaoks on see kõige olulisem: see töötab oma omaniku õigustega, tavaliselt `postgres`, mis jätab RLS-i vahele. Kui kutsuja saab juhtida, millist `admins` tabelit funktsioon loeb, juhib ta kontrolli, mis töötab kasutajana `postgres`.

## Kas seda saab minu testis ära kasutada?

Kohalikus Postgres 17.10-s tegin tabeli `public.admins` ühe adminiga ja neli versiooni samast funktsioonist, `select exists (select 1 from admins where user_id = uid)`, kõik `SECURITY DEFINER`. Seejärel logisin sisse väheste õigustega rollina, mis saab käivitada SQL-i ja millel on vaikimisi õigus luua ajutisi tabeleid, ning lõin tabeli `pg_temp.admins`, kus oli kasutaja A, kes pole admin:

![is_admin(A) pärast ajutist tabelit admins. SECURITY DEFINER funktsioon, kohalik Postgres 17.10. Ilma search_path: pg_temp.admins → admins → temp → true; search_path = public: pg_temp.admins → admins → temp → true; search_path = '' + public.admins: pg_temp.admins → public.admins → false.](https://madsalt.tech/charts/et/supabase-function-search-path-mutable.svg)

*Minu reproduktsioon kohalikul Postgresil, 24. oktoober 2026.*

| Funktsiooni seade                             | Lint'i tingimus | `is_admin(A)` pärast ajutist tabelit |
| --------------------------------------------- | --------------- | ------------------------------------ |
| puudub                                        | märgitud        | `true`                               |
| `set search_path = public`                    | läbib           | `true`                               |
| `set search_path = ''`, kehas `public.admins` | läbib           | `false`                              |
| `set search_path = public, pg_temp`           | läbib           | `false`                              |

Teine rida üllatas mind. Supabase'i hooldaja [kirjutas 2024. aastal](https://github.com/supabase/splinter/issues/100), et fikseeritud mittetühi tee ei kanna turvariski, ja lint võtab selle vastu. Postgres aga otsib esmalt ajutisest skeemist, kui teel pole nimetatud `pg_temp`, nagu hoiatab tema [SECURITY DEFINER funktsioonide kirjutamise dokumentatsioon](https://www.postgresql.org/docs/current/sql-createfunction.html#SQL-CREATEFUNCTION-SECURITY). Seega `search_path = public` laseb ajutisel tabelil skeemita nime ikkagi varjata.

## Kes saab seda Supabase'is tegelikult teha?

Mitte külastaja teie rakenduse kaudu. Data API ei saa luua ajutisi tabeleid ega muuta sessiooni `search_path`'i, nii et ainult publishable key sinna ei jõua. Vaja on otsest andmebaasiühendust: teist teenust oma sisselogimisega, BI- või aruandlustööriista, töövõtja ainult lugemise rolli, lekkinud connection string'i. Enamikus väikestes rakendustes on risk väike; igas projektis, kus andmebaasi sisselogimised on teistel inimestel või tööriistadel peale teie, parandage definer-funktsioonid esimesena.

## Kuidas seda parandada?

Looge funktsioon uuesti tühja teega ja skeemanimedega kehas:

```sql
create or replace function public.is_admin(uid uuid)
returns boolean
language sql stable security definer
set search_path = ''
as $$ select exists (select 1 from public.admins where user_id = uid) $$;

revoke execute on function public.is_admin(uuid) from public, anon;
```

`revoke` on sama oluline kui tee: `public` skeemi definer-funktsiooni saab kutsuda Data API kaudu, nii et ilma selleta võib iga külaline küsida aadressilt `/rpc/is_admin`, kas antud kasutaja on admin. Andke õigus tagasi ainult rollidele, kes seda vajavad, või hoidke sellised abifunktsioonid skeemis, mida API ei avalda.

Ärge käivitage ainult `alter function public.is_admin(uuid) set search_path = ''`. See vaigistab Advisori ja rikub funktsiooni: minu käivitusel nurjus järgmine kutse veaga `42P01: relation "admins" does not exist`. Laiendite operaatorid vajavad samuti oma skeemi, näiteks `operator(extensions.<=>)` pgvectori jaoks.

Loend sellest, mida lint `public` skeemis märgib, definer-funktsioonid esimesena:

```sql
select p.proname, p.prosecdef as security_definer
from pg_proc p join pg_namespace n on n.oid = p.pronamespace
where n.nspname = 'public'
  and not exists (select 1 from unnest(coalesce(p.proconfig, '{}')) c
                  where c like 'search_path=%')
order by p.prosecdef desc, p.proname;
```

## Kas parandus maksab midagi?

Mõnikord. Iga `set` klausel takistab Postgresil lihtsat SQL funktsiooni seda kutsuvasse päringusse sisse lülitamast, nagu [GitHubis teatatud](https://github.com/supabase/supabase/issues/33131). Mõõtsin mõlemat kuju 200 000 real, filtreeritaval veerul indeks (mediaan 7 käivitusest):

| SQL funktsioon, seejärel filtreeritud omaniku järgi | Ilma `set`                 | `set search_path = ''` |
| --------------------------------------------------- | -------------------------- | ---------------------- |
| Filter väljas: `visible_items() where owner = ...`  | 0,053 ms, indeks kasutusel | 36,7 ms, full scan     |
| Filter sees: `items_of(owner)`                      | 0,056 ms                   | 0,082 ms               |

Kui hulka tagastavat SQL funktsiooni päritakse filtriga selle väljaspool, viige filter enne tee fikseerimist parameetrina sisse.

## Kontrollige oma projekti

- Parandage Advisori nimekirjas esimesena `SECURITY DEFINER` funktsioonid; invoker-funktsioonid töötavad niikuinii kutsuja õigustega.
- Tasuta [Supabase'i turvakontroll](https://madsalt.tech/et/tools/supabase-security-check/) näitab Advisori leide oma reeglite kõrval, sealhulgas API kaudu kutsutavaid definer-funktsioone ja definer-funktsioone, mis kontrollivad `current_user`'it.
- Rohkem selle kohta, mida definer-funktsioonid võivad vahele jätta, on märkuses [NULL PL/pgSQL-i IF NOT-is jättis 3683 ülesande kontrollita](https://madsalt.tech/et/notes/plpgsql-if-not-null-fails-open/) ja selliseid abifunktsioone kutsuvad poliitikad on artiklis [Supabase RLS policy näited, testitud API kaudu](https://madsalt.tech/et/blog/supabase-rls-policy-examples/).
