Liigu sisu juurde

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

Supabase

Vaata MarkdowninaAva rakenduses ClaudeAva rakenduses ChatGPTAva rakenduses Perplexity

Küsimus kopeeritakse ka. Kui vestlus avaneb tühjana, kleepige see sisse.

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.

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 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.
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, 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. 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:

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:

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. 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

© 2026 Denys Zaichenko. Algne artikkel: https://madsalt.tech/et/notes/supabase-function-search-path-mutable/