Īsumā
raw_user_meta_data glabā visu, ko pārlūks nodeva supabase.auth.signUp(). Vienā produkcijas lietotnē handle_new_user trigeris no turienes nolasīja jaunā lietotāja lomu, tāpēc jebkurš varēja reģistrēties ar Owner lomas id un pārņemt kontu. Labojums: loma nāk no tabulas, ko raksta tikai serveris un kas tiek aizpildīta pirms ielūguma nosūtīšanas.
Tas notika revīzijas uzņēmuma darba laika uzskaites lietotnē, Supabase lietotnē, kur katrs piekļuves noteikums dzīvo datubāzē. Kļūda bija trigerī, kas katram jaunam lietotājam izveido profilu.
Ko darīja trigeris?
Vienkāršotā veidā tas izskatījās šādi:
create function public.handle_new_user()
returns trigger
language plpgsql
security definer set search_path = ''
as $$
declare
_role_id uuid := (new.raw_user_meta_data ->> 'role_id')::uuid;
begin
insert into public.profiles (id, full_name, role_id)
values (new.id, new.raw_user_meta_data ->> 'full_name', _role_id);
return new;
end;
$$;
Ielūgumu plūsma tur ielika pareizo role_id, tāpēc ierastā lietojumā tas strādāja. Taču raw_user_meta_data ir reģistrācijas options.data, un tā saturu nosaka pārlūks:
await supabase.auth.signUp({
email: 'me@example.com',
password: '...',
options: { data: { role_id: '<owner role uuid>' } },
})
Atļauju pārbaude īpašniekiem atgrieza true, pirms skatījās uz jebko citu, tāpēc šis viens lauks deva pilnu kontroli pār kontu. Pašas Supabase Users guide saka, ka lietotāja metadatus nedrīkst izmantot RLS politikās vai autorizācijas loģikā, jo lietotājs tos var rediģēt bez jebkādām pārbaudēm.
Kas to izlaboja?
Loma tagad nāk no privātas tabulas, kurai klients nevar piekļūt:
create table private.pending_invites (
email text primary key,
role_id uuid,
invited_by uuid,
created_at timestamptz default now()
);
revoke all on table private.pending_invites from anon, authenticated;
Ielūguma funkcija darbojas serverī pēc tam, kad pārbaudīta ielūdzēja atļauja. Tā vispirms ieraksta gaidošo ielūgumu un tikai tad izveido ielūguma saiti. Trigeris atrod lomu pēc e-pasta un izdzēš rindu. Vārds joprojām nāk no metadatiem, un tas ir kārtībā: tie ir attēlošanas dati.
Secībai ir nozīme. Ielūgums lietotāju izveido uzreiz: Supabase Users guide norāda, ka jauna e-pasta ielūgšana izveido neapstiprinātu lietotāju. Trigeris iedarbojas tajā brīdī, tāpēc gaidošajai rindai jau jābūt.
Kā pārbaudīt savu lietotni?
Atveriet savu handle_new_user funkciju vai jebkuru trigeri uz auth.users un meklējiet raw_user_meta_data. Vārds un avatārs no turienes ir kārtībā. Loma, uzņēmums, plāns, nomnieks vai jebkas cits, kas dod piekļuvi, jāņem no tabulas vai no raw_app_meta_data, ko lietotājs mainīt nevar.
Tad pamēģiniet: reģistrējieties caur API, ierakstot options.data laukā role_id vai role: 'admin'. Jaunajam kontam nevajadzētu iegūt neko papildus.
Šāda pārbaude ir mana RLS testēšanas metodes pirmais solis. Vairāku nomnieku lietotnēm skatiet arī ko RLS izlaiž lietotājam divās org.. Pārējās pārbaudes, ko veicu katrā Supabase lietotnē, ir manā Lovable lietotnes drošības kontrolsarakstā. Pirmais, ko skatos Dashboard, ir kuras shēmas atklāj Data API. Supabase drošības pārbaude aptver lomas, tiesības, politikas un autentifikācijas iestatījumus pret 45 OWASP Top 10:2025 noteikumiem, bet ne to, ko trigeris pārkopē no reģistrācijas metadatiem, tāpēc šī paliek manuāla pārbaude.