---
title: "Supabase \"function search path mutable\": ko tas nozīmē"
description: "Ko nozīmē Advisor brīdinājums function_search_path_mutable, kurš to var izmantot, kāpēc search_path = public manā testā nepietika un kā to labot."
url: "https://madsalt.tech/lv/notes/supabase-function-search-path-mutable/"
author: "Denys Zaichenko"
author_url: "https://madsalt.tech/lv/about/"
language: "lv"
published: 2026-11-01
---

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

Ī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](https://github.com/bdougie/contributor.info/commit/3c73dda01df80faccb75278ec0f826a84e01a6d9).

## 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](https://supabase.com/docs/guides/database/database-linter?lint=0011_function_search_path_mutable) 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.](https://madsalt.tech/charts/lv/supabase-function-search-path-mutable.svg)

*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](https://github.com/supabase/splinter/issues/100), 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](https://www.postgresql.org/docs/current/sql-createfunction.html#SQL-CREATEFUNCTION-SECURITY). 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ā:

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

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

## 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](https://github.com/supabase/supabase/issues/33131). 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

- Advisor sarakstā vispirms labojiet `SECURITY DEFINER` funkcijas; invoker funkcijas tāpat darbojas ar izsaucēja tiesībām.
- Bezmaksas [Supabase drošības pārbaude](https://madsalt.tech/lv/tools/supabase-security-check/) rāda Advisor atradumus līdzās savām pārbaudēm, ieskaitot definer funkcijas, kuras var izsaukt caur API, un definer funkcijas, kas pārbauda `current_user`.
- Vairāk par to, ko definer funkcijas var izlaist, ir piezīmē [NULL PL/pgSQL IF NOT izlaida pārbaudi 3683 uzdevumiem](https://madsalt.tech/lv/notes/plpgsql-if-not-null-fails-open/), bet politikas, kas izsauc šādas palīgfunkcijas, ir rakstā [Supabase RLS policy piemēri, pārbaudīti caur API](https://madsalt.tech/lv/blog/supabase-rls-policy-examples/).
