Siirry sisältöön

Supabase "function search path mutable": mitä se tarkoittaa

Supabase

Näytä MarkdowninaAvaa palvelussa ClaudeAvaa palvelussa ChatGPTAvaa palvelussa Perplexity

Kysymys kopioidaan myös. Jos keskustelu avautuu tyhjänä, liitä se.

TL;DR

Varoitus tarkoittaa, että funktiolla ei ole kiinteää search_path-asetusta, joten jokainen sen sisällä oleva ilman skeemaa kirjoitettu nimi, kuten admins, haetaan niin kuin kutsujan istunto sanoo. Paikallisessa testissäni SECURITY DEFINER -funktio is_admin() palautti true käyttäjälle, joka ei ole admin, kun tämä oli luonut väliaikaisen taulun nimeltä admins, eikä kiinteä search_path = public pysäyttänyt sitä. Toimi set search_path = '', kun jokainen taulu kirjoitetaan muodossa public.admins.

Supabasen Security Advisor listaa tämän lintiksi 0011, “Function Search Path Mutable”, taso WARN, tarkenteella “Function public.x has a role mutable search_path”. Se liputtaa jokaisen funktion, jolla asetusta ei ole, myös SECURITY INVOKER -funktiot, joten projektissa, jossa on paljon apufunktioita, lista venyy pitkäksi: yksi avoimen lähdekoodin projekti korjasi niistä 99 yhdellä migraatiolla.

Mitä “role mutable search_path” tarkoittaa?

search_path on lista skeemoista, joista Postgres etsii nimeä, jonka edessä ei ole skeemaa. Funktio, jolla ei ole omaa asetusta, käyttää kutsujan listaa. Supabasen lint-sivu suosittelee asettamaan sen tyhjäksi merkkijonoksi, mikä pakottaa kirjoittamaan jokaisen funktion sisällä olevan viittauksen täydellä skeemanimellä.

SECURITY DEFINER -funktiolle tällä on eniten merkitystä: se ajetaan omistajansa oikeuksilla, yleensä postgres, joka ohittaa RLS:n. Jos kutsuja voi ohjata, mitä admins-taulua funktio lukee, kutsuja ohjaa tarkistusta, joka ajetaan käyttäjänä postgres.

Voiko tätä hyödyntää testissäni?

Paikallisessa Postgres 17.10:ssä tein taulun public.admins, jossa oli yksi admin, ja neljä versiota samasta funktiosta, select exists (select 1 from admins where user_id = uid), kaikki SECURITY DEFINER. Sitten kirjauduin sisään vähäoikeuksisena roolina, joka voi ajaa SQL:ää ja jolla on oletuksena oikeus luoda väliaikaisia tauluja, ja loin taulun pg_temp.admins, jossa oli käyttäjä A, joka ei ole admin:

is_admin(A) väliaikaisen admins-taulun jälkeen. SECURITY DEFINER -funktio, paikallinen Postgres 17.10. Ei 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.
Toistoni paikallisella Postgresilla, 24. lokakuuta 2026.
Funktion asetus Lint-ehto is_admin(A) väliaikaisen taulun jälkeen
ei mitään liputettu true
set search_path = public läpäisee true
set search_path = '', rungossa public.admins läpäisee false
set search_path = public, pg_temp läpäisee false

Toinen rivi yllätti minut. Supabasen ylläpitäjä kirjoitti vuonna 2024, ettei kiinteä, ei-tyhjä polku aiheuta tietoturvariskiä, ja lint hyväksyy sen. Postgres kuitenkin hakee ensin väliaikaisesta skeemasta, ellei polussa mainita pg_temp, kuten sen SECURITY DEFINER -funktioiden kirjoittamista käsittelevä dokumentaatio varoittaa. Siis search_path = public antaa väliaikaisen taulun silti peittää skeematon nimi.

Kuka tämän voi oikeasti tehdä Supabasessa?

Ei sivuston kävijä sovelluksesi kautta. Data API ei voi luoda väliaikaisia tauluja eikä muuttaa istunnon search_path-asetusta, joten pelkkä publishable key ei riitä. Tarvitaan suora tietokantayhteys: toinen palvelu omalla tunnuksellaan, BI- tai raportointityökalu, ulkopuolisen tekijän vain luku -rooli tai vuotanut connection string. Useimmissa pienissä sovelluksissa riski on pieni; projektissa, jossa tietokantatunnuksia on muillakin ihmisillä tai työkaluilla kuin sinulla, korjaa definer-funktiot ensin.

Miten se korjataan?

Luo funktio uudelleen tyhjällä polulla ja skeemanimillä rungossa:

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 yhtä tärkeä kuin polku: public-skeeman definer-funktio on kutsuttavissa Data API:n kautta, joten ilman sitä kuka tahansa vieras voi kysyä osoitteesta /rpc/is_admin, onko tietty käyttäjä admin. Anna oikeus takaisin vain rooleille, jotka sitä tarvitsevat, tai pidä tällaiset apufunktiot skeemassa, jota API ei julkaise.

Älä aja pelkkää alter function public.is_admin(uuid) set search_path = ''. Se vaientaa Advisorin ja rikkoo funktion: ajossani seuraava kutsu epäonnistui virheeseen 42P01: relation "admins" does not exist. Laajennusten operaattorit tarvitsevat myös skeemansa, esimerkiksi operator(extensions.<=>) pgvectorille.

Lista siitä, mitä lint liputtaa public-skeemassa, definer-funktiot ensin:

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;

Maksaako korjaus jotain?

Joskus. Mikä tahansa set-lauseke estää Postgresia upottamasta tavallista SQL-funktiota sitä kutsuvaan kyselyyn, kuten GitHubissa on raportoitu. Mittasin molemmat muodot 200 000 rivillä, suodatettavassa sarakkeessa indeksi (mediaani 7 ajosta):

SQL-funktio, sitten suodatus omistajan mukaan Ilman set set search_path = ''
Suodatin ulkopuolella: visible_items() where owner = ... 0,053 ms, indeksi käytössä 36,7 ms, full scan
Suodatin sisällä: items_of(owner) 0,056 ms 0,082 ms

Jos joukon palauttavaa SQL-funktiota kysytään suodattimella sen ulkopuolella, siirrä suodatin parametriksi funktion sisään ennen kuin lukitset polun.

Tarkista projektisi

© 2026 Denys Zaichenko. Alkuperäinen artikkeli: https://madsalt.tech/fi/notes/supabase-function-search-path-mutable/