Pāriet uz saturu

Supabase "function search path mutable": ko tas nozīmē

Supabase

Skatīt kā MarkdownAtvērt pakalpojumā ClaudeAtvērt pakalpojumā ChatGPTAtvērt pakalpojumā Perplexity

Jautājums tiek arī nokopēts. Ja tērzēšana atveras tukša, ielīmējiet to.

Īsumā

Brīdinājums nozīmē, ka funkcijai nav fiksēta search_path, tāpēc katrs nekvalificēts nosaukums tās iekšienē, piemēram, admins, tiek meklēts tā, kā liek izsaucēja sesija. Manā lokālajā testā SECURITY DEFINER funkcija is_admin() atgrieza true lietotājam, kurš nav administrators, pēc tam, kad viņš izveidoja pagaidu tabulu ar nosaukumu admins, un arī fiksēts search_path = public to neapturēja. Palīdzēja set search_path = '', katru tabulu rakstot kā public.admins.

Supabase Security Advisor to uzrāda kā lint 0011, “Function Search Path Mutable”, līmenis WARN, ar detaļu “Function public.x has a role mutable search_path”. Tas atzīmē katru funkciju bez šī iestatījuma, arī SECURITY INVOKER, tāpēc projektā ar daudzām palīgfunkcijām saraksts kļūst garš: viens atvērtā koda projekts salaboja 99 no tām ar vienu migrāciju.

Ko nozīmē “role mutable search_path”?

search_path ir shēmu saraksts, kurā Postgres meklē nosaukumu, kuram priekšā nav shēmas. Funkcija bez sava iestatījuma izmanto izsaucēja sarakstu. Supabase lint lapa iesaka to iestatīt uz tukšu virkni, kas liek katru atsauci funkcijas iekšienē rakstīt ar pilnu shēmas nosaukumu.

Funkcijai ar SECURITY DEFINER tam ir vislielākā nozīme: tā darbojas ar sava īpašnieka tiesībām, parasti postgres, kas apiet RLS. Ja izsaucējs var ietekmēt, kuru tabulu admins funkcija lasa, viņš ietekmē pārbaudi, kas darbojas kā postgres.

Vai to var izmantot manā testā?

Lokālā Postgres 17.10 izveidoju tabulu public.admins ar vienu administratoru un četras tās pašas funkcijas versijas, select exists (select 1 from admins where user_id = uid), visas ar SECURITY DEFINER. Pēc tam pieteicos kā zemu tiesību loma, kas var izpildīt SQL un kam pēc noklusējuma ir tiesības veidot pagaidu tabulas, un izveidoju pg_temp.admins ar lietotāju A, kurš nav administrators:

is_admin(A) pēc pagaidu tabulas admins. SECURITY DEFINER funkcija, lokālais Postgres 17.10. Bez 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.
Mana reprodukcija lokālā Postgres vidē, 2026. gada 24. oktobris.
Funkcijas iestatījums Lint nosacījums is_admin(A) pēc pagaidu tabulas
nav atzīmēts true
set search_path = public iztur true
set search_path = '', pamattekstā public.admins iztur false
set search_path = public, pg_temp iztur false

Otrā rinda mani pārsteidza. Supabase uzturētājs 2024. gadā rakstīja, ka fiksēts netukšs ceļš nerada drošības risku, un lint to pieņem. Taču Postgres vispirms meklē pagaidu shēmā, ja ceļā nav minēts pg_temp, kā brīdina tā dokumentācija par SECURITY DEFINER funkciju rakstīšanu. Tātad search_path = public joprojām ļauj pagaidu tabulai aizēnot nekvalificētu nosaukumu.

Kurš to Supabase tiešām var izdarīt?

Ne apmeklētājs caur jūsu lietotni. Data API nevar veidot pagaidu tabulas vai mainīt sesijas search_path, tāpēc ar publishable key vien nepietiek. Vajadzīgs tiešs savienojums ar datubāzi: otrs pakalpojums ar savu pieteikšanos, BI vai atskaišu rīks, darbuzņēmēja tikai lasīšanas loma, noplūdis connection string. Lielākajā daļā mazu lietotņu risks ir zems; jebkurā projektā, kur datubāzes pieteikšanās ir citiem cilvēkiem vai rīkiem, nevis tikai jums, vispirms salabojiet definer funkcijas.

Kā to salabot?

Izveidojiet funkciju no jauna ar tukšu ceļu un shēmu nosaukumiem pamattekstā:

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 ir tikpat svarīgs kā ceļš: definer funkciju shēmā public var izsaukt caur Data API, tāpēc bez tā jebkurš viesis var pa adresi /rpc/is_admin pajautāt, vai konkrētais lietotājs ir administrators. Atdodiet tiesības tikai lomām, kurām tās vajadzīgas, vai turiet šādas palīgfunkcijas shēmā, ko API neatklāj.

Neizpildiet tikai alter function public.is_admin(uuid) set search_path = ''. Tas apklusina Advisor un salauž funkciju: manā izpildē nākamais izsaukums beidzās ar 42P01: relation "admins" does not exist. Paplašinājumu operatoriem arī vajadzīga sava shēma, piemēram, operator(extensions.<=>) pgvector gadījumā.

Saraksts ar to, ko lint atzīmēs shēmā public, definer funkcijas pirmās:

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;

Vai labojums kaut ko maksā?

Dažreiz. Jebkura set klauzula neļauj Postgres iekļaut vienkāršu SQL funkciju to izsaucošajā vaicājumā, kā ziņots GitHub. Izmēru abas formas ar 200 000 rindām un indeksu filtrētajā kolonnā (mediāna no 7 izpildēm):

SQL funkcija, pēc tam filtrēta pēc īpašnieka Bez set set search_path = ''
Filtrs ārpusē: visible_items() where owner = ... 0,053 ms, indekss izmantots 36,7 ms, full scan
Filtrs iekšpusē: items_of(owner) 0,056 ms 0,082 ms

Ja kopu atgriezošu SQL funkciju vaicā ar filtru ārpus tās, pirms ceļa fiksēšanas pārvietojiet filtru iekšā kā parametru.

Pārbaudiet savu projektu

© 2026 Denys Zaichenko. Oriģinālais raksts: https://madsalt.tech/lv/notes/supabase-function-search-path-mutable/