Späť na blog
13. mája 2026

Chybná konfigurácia Supabase RLS: Ako chýbajúca politika odhalila profil každého používateľa

Viktor Bulanek
Founder & CTO, Penetrify
MSc IT Security · 20+ years in security · 4x Ex-CTO

Aplikácia vyzerala pripravená na produkciu. Čisté používateľské rozhranie, funkčná integrácia Stripe, prepracovaný proces registrácie. Bola predstavená na Product Hunt, získala viac ako 200 používateľov v prvom týždni a už generovala MRR. Zakladateľ ju postavil za 48 hodín počas hackathonového víkendu pomocou Next.js a Supabase, preferovanej technológie pre každého, kto chce rýchlo uviesť produkt na trh.

Osem minút po spustení skenovania Penetrify sme označili kritické zistenie: záznam profilu každého používateľa – meno, e-mail, metaúdaje účtu – bol čitateľný akýmkoľvek iným autentifikovaným používateľom prostredníctvom automaticky generovaného REST API Supabase. Nevyžadovala sa žiadna sofistikovaná útočná technika. Stačilo vymeniť svoje ID používateľa za iné v URL adrese.

Toto je príbeh o tom, ako sa to stalo, prečo je to bežnejšie, než si ktokoľvek chce priznať, a ako presne vyzerala oprava.


Čo je Supabase Row Level Security — A čo sa stane, keď je vypnuté

Supabase je postavené na PostgreSQL a priamo sprístupňuje vaše databázové tabuľky cez REST API (prostredníctvom PostgREST) a klientsku knižnicu JavaScript. To je skutočne silné pre rýchly vývoj: môžete sa dotazovať na svoju databázu z frontendu bez napísania jedinej API trasy.

Mechanizmus, ktorý bráni používateľom čítať si navzájom údaje, sa nazýva Row Level Security (RLS). RLS je funkcia PostgreSQL, ktorá vám umožňuje definovať pravidlá kontrolujúce, ktoré riadky môže daný používateľ databázy SELECT, INSERT, UPDATE alebo DELETE. V aplikácii Supabase by ste zvyčajne napísali pravidlo ako:

-- Povoliť používateľom čítať iba ich vlastný profil
CREATE POLICY "Users can view own profile"
  ON profiles
  FOR SELECT
  USING (auth.uid() = user_id);

Keď je RLS povolené a je zavedené takéto pravidlo, dotaz na profil iného používateľa vráti nulový počet riadkov — databáza vynucuje kontrolu prístupu na úrovni riadkov, skôr než sa akékoľvek údaje dostanú do aplikácie.

Keď je RLS zakázané alebo neexistuje žiadne pravidlo, tabuľka sa správa, akoby bol každý riadok verejný pre akúkoľvek autentifikovanú požiadavku. REST API Supabase, dostupné na https://[project].supabase.co/rest/v1/profiles, vráti všetky riadky v tabuľke – údaje každého používateľa – každému, kto má platný JWT z daného projektu.


Čo sme zistili: Päť zistení, dve z nich kritické

Skenovanie prebiehalo osem minút v rýchlom režime proti živej aplikácii. Tu sú zistenia v poradí podľa závažnosti:

KRITICKÉ — Supabase RLS nie je povolené v tabuľke profilov

Tabuľka profilov mala RLS zakázané. Akýkoľvek autentifikovaný používateľ ju mohol dotazovať prostredníctvom REST endpointu Supabase a získať všetky záznamy používateľov. Požiadavka, ktorá to demonštrovala:

GET /rest/v1/profiles?select=*
Authorization: Bearer [any valid user JWT]

HTTP/1.1 200 OK
[
  {"id": "uuid-1", "email": "user1@example.com", "full_name": "...", ...},
  {"id": "uuid-2", "email": "user2@example.com", "full_name": "...", ...},
  ... (všetky záznamy 200+ používateľov)
]

Podľa GDPR ide o únik osobných údajov, ktorý ovplyvňuje každého registrovaného používateľa. Anonymný kľúč Supabase je zámerne vložený do frontendového JavaScript balíka — je bezpečné ho verejne vystaviť, keď je RLS správne nakonfigurované, pretože samotný kľúč neposkytuje žiadny zvýšený prístup. Bez RLS sa stáva hlavným kľúčom k všetkým používateľským údajom.

KRITICKÉ — Overenie e-mailu nie je vynucované na chránených koncových bodoch

Supabase štandardne umožňuje registrácie pomocou e-mailu a hesla a odosiela potvrdzovací e-mail na overenie adresy. Avšak backendové API trasy aplikácie nekontrolovali, či si žiadajúci používateľ potvrdil svoj e-mail pred udelením prístupu k chránenej funkcionalite.

Útočník sa mohol zaregistrovať s victim@example.com (skutočná e-mailová adresa používateľa), úplne preskočiť overenie e-mailu a okamžite získať prístup k chráneným API trasám aplikácie, akoby vlastnil daný e-mail. V kombinácii s problémom RLS to znamenalo, že neautentifikovaný útočník mohol exfiltrovať celú používateľskú databázu vytvorením jednorazového účtu s akoukoľvek e-mailovou adresou.

MEDIUM — IDOR na /api/export

Aplikácia mala exportný koncový bod, ktorý akceptoval ID používateľa ako parameter dotazu:

GET /api/export?userId=abc123

Na strane servera sa nevykonávala žiadna kontrola vlastníctva. Akýkoľvek autentifikovaný používateľ mohol exportovať údaje akéhokoľvek iného používateľa nahradením svojho vlastného ID ID cieľa. ID používateľov boli vystavené v API odpovediach v celej aplikácii, čo robilo enumeráciu triviálnou.

MEDIUM — Žiadne obmedzenie rýchlosti na prihlasovacom koncovom bode

Prihlasovací koncový bod akceptoval autentifikačné požiadavky približne 500 požiadaviek za sekundu bez obmedzenia alebo uzamknutia. Útok typu credential stuffing proti používateľskej základni aplikácie by nenarazil na žiadny odpor.

MEDIUM — JWT tokeny uložené v localStorage bez rotácie

JWT tokeny Supabase boli uložené v localStorage, prístupné akémukoľvek JavaScriptu bežiacemu na stránke. Pri zmenách oprávnení nedochádzalo k rotácii tokenov. Úspešný XSS útok na akejkoľvek stránke by útočníkovi poskytol perzistentnú, platnú reláciu.


Prečo sa to deje: Pasca predvolených nastavení Supabase

Toto nie je príbeh o neopatrnom vývojárovi. Je to príbeh o predvolených nastaveniach.

Keď vytvoríte novú tabuľku v Supabase, RLS je predvolene vypnuté. Vlastná dokumentácia Supabase to jasne popisuje a odporúča jeho zapnutie, ale príklady rýchleho štartu — tie, ktoré vývojári skutočne sledujú pri tvorbe o 2 ráno počas hackathonu — často vynechávajú RLS kvôli stručnosti. Vidíte funkčný dotaz v príklade, skopírujete vzor, nasadíte ho.

Dashboard Supabase zobrazuje žltú ikonu upozornenia pri tabuľkách bez RLS. Je ľahké si to nevšimnúť, keď sa sústredíte na UI, integráciu platieb, proces onboardingu. Neexistuje žiadna chyba, žiadne zlyhanie za behu, žiadny zjavný symptóm. Všetko funguje perfektne. Používatelia sa môžu registrovať, prihlasovať a používať aplikáciu. Zraniteľnosť je úplne tichá.

Najnebezpečnejšie bezpečnostné chyby sú tie, ktoré vyzerajú presne ako správne správanie.

Tento vzor sa objavuje takmer v každej aplikácii podporovanej Supabase, ktorú skenujeme a ktorá bola postavená s dôrazom na rýchlosť. Nie preto, že by sa vývojári nestarali o bezpečnosť, ale preto, že časový tlak hackathonu alebo launch sprintu nenecháva priestor na prečítanie každej sekcie dokumentácie.


Riešenie: Dve hodiny, žiadne prepisovanie kódu

Zakladateľ opravil všetkých päť zistení za menej ako dve hodiny v ten istý večer, keď správa dorazila. Tu je presne to, čo bolo urobené:

RLS — 15 minút v dashboarde Supabase

Povolenie RLS a pridanie vhodných politík nevyžadovalo žiadne zmeny kódu. V dashboarde Supabase, pod Table Editor → profiles → RLS Policies:

-- Enable RLS on the table (one toggle in the dashboard)
-- Then add policies:

CREATE POLICY "Users can view own profile"
  ON profiles FOR SELECT
  USING (auth.uid() = user_id);

CREATE POLICY "Users can update own profile"
  ON profiles FOR UPDATE
  USING (auth.uid() = user_id);

-- For admin access (if needed):
CREATE POLICY "Service role has full access"
  ON profiles
  USING (auth.role() = 'service_role');

Po povolení RLS a pridaní týchto politík hromadný dotaz vrátil nula riadkov pre akéhokoľvek autentifikovaného používateľa, ktorý požiadal o údaje, ktoré mu nepatrili.

Overenie e-mailu — jedna kontrola v middleware

API trasy Next.js už čítali objekt používateľa Supabase z JWT pri každej požiadavke. Pridanie vynútenia overenia e-mailu bola jednoradová kontrola v autentifikačnom middleware:

const { data: { user } } = await supabase.auth.getUser()
if (!user?.email_confirmed_at) {
  return res.status(403).json({ error: 'Email verification required' })
}

IDOR na /api/export — oprava middleware na jednom riadku

Oprava spočívala v nahradení používateľom dodaného parametra userId vlastným ID overeného používateľa, extrahovaným z overeného JWT:

// Before (vulnerable)
const userId = req.query.userId

// After (fixed)
const { data: { user } } = await supabase.auth.getUser()
const userId = user.id  // always the authenticated user — can't be spoofed

Obmedzenie rýchlosti požiadaviek — vstavané obmedzenie rýchlosti požiadaviek od Vercel

Aplikácia bola hostovaná na Vercel. Pridanie obmedzenia rýchlosti požiadaviek na prihlasovací koncový bod si vyžiadalo pridanie balíka @upstash/ratelimit a obalenie routy — približne 20 riadkov kódu. Zakladateľ túto opravu nasadil nasledujúce ráno.


Vystavenie GDPR

Problém s RLS ovplyvnil všetkých viac ako 200 registrovaných používateľov. Ich kompletné profilové záznamy — e-mailové adresy, zobrazované mená a akékoľvek iné polia uložené v tabuľke profilov — boli čitateľné akýmkoľvek iným overeným používateľom po celý čas, čo bola aplikácia v prevádzke.

Podľa článku 33 GDPR musí byť narušenie osobných údajov, ktoré „pravdepodobne povedie k riziku pre práva a slobody fyzických osôb“, nahlásené príslušnému dozornému orgánu do 72 hodín od zistenia. Či toto konkrétne narušenie prekročilo túto hranicu, by záviselo od citlivosti uložených údajov a od toho, koľko používateľských údajov bolo skutočne sprístupnených — ale okno vystavenia bolo otvorené.

Zakladateľ vymenil všetky citlivé konfiguračné hodnoty, povolil RLS a opravil zostávajúce problémy v ten istý večer. V logoch Supabase sa nenašli žiadne dôkazy o neoprávnenom prístupe. Problém bol obmedzený skôr, než sa stal incidentom.


Ako skontrolovať vlastnú aplikáciu Supabase

Ak prevádzkujete aplikáciu podporovanú Supabase, tu je rýchly samoaudit, ktorý môžete vykonať za päť minút:

  1. Otvorte panel Supabase → Editor tabuliek. Akákoľvek tabuľka bez ikony zeleného štítu má RLS vypnuté. Ak táto tabuľka obsahuje používateľské údaje, je pravdepodobne vystavená.
  2. Otvorte vývojárske nástroje prehliadača vo vašej produkčnej aplikácii → záložka Sieť → filtrujte podľa URL vášho projektu Supabase. Hľadajte požiadavky na /rest/v1/[tablename]?select=*. Ak vidíte požiadavky vracajúce mnoho záznamov, skontrolujte, či by mali byť obmedzené na overeného používateľa.
  3. Skontrolujte svoj tok overenia e-mailu. Zaregistrujte si nový účet, preskočte potvrdzovací e-mail a pokúste sa priamo pristupovať k chráneným častiam vašej aplikácie. Ak sa dostanete k chránenej funkcionalite bez potvrdenia e-mailu, váš backend nevynucuje overenie.
  4. Skontrolujte svoje koncové body pre export/stiahnutie. Akýkoľvek koncový bod, ktorý akceptuje ID používateľa ako parameter, by ho mal krížovo skontrolovať s JWT overeného používateľa. Ak je možné parameter voľne nahradiť pre prístup k údajom iného používateľa, ide o IDOR.

Tieto štyri kontroly trvajú menej ako desať minút a pokrývajú najčastejšie bezpečnostné medzery Supabase, ktoré vidíme v produkčných aplikáciách.


Širší vzor

Táto prípadová štúdia nie je nezvyčajná. Je reprezentatívna pre to, čo nachádzame vo väčšine aplikácií podporovaných Supabase, ktoré boli vytvorené počas hackathonu, rýchleho štartovacieho šprintu alebo osamelým zakladateľom bez bezpečnostného pozadia.

Kombinácia rýchlych nástrojov, vynikajúcej vývojárskej skúsenosti a verejných predvolených nastavení, ktoré uprednostňujú jednoduchosť použitia pred bezpečnosťou, znamená, že mnohé aplikácie sa dodávajú s týmito medzerami. Medzery sú opraviteľné — často v priebehu minút, zriedka si vyžadujú niečo viac ako SQL politiku alebo kontrolu middleware na jednom riadku. Ťažké je vedieť, že vôbec existujú.

Tím Supabase vykonal značnú prácu, aby bolo RLS výraznejšie na ovládacom paneli a v dokumentácii. Priepasť medzi „dokumentácia hovorí, aby sa to povolilo“ a „každá produkčná aplikácia to má skutočne povolené“ však zostáva široká. Kým sa automatizované bezpečnostné testovanie nestane súčasťou štandardného kontrolného zoznamu pred spustením, tento vzor sa bude naďalej objavovať.

Frequently Asked Questions

Aké typy zraniteľností Penetrify detekuje?

Penetrify detekuje všetky kategórie zraniteľností OWASP Top 10 vrátane SQL injection, XSS, CSRF, IDOR, nefunkčnej autentifikácie, bezpečnostných miskonfigurácií a úniku citlivých dát. Testuje tiež bezpečnosť API, správu relácií a bežné miskonfigurácie v Supabase, Firebase a Bubble.

Ako dlho trvá AI penetračný test?

Rýchle skenovanie je dokončené za 15–30 minút. Štandardné skenovanie trvá 1–2 hodiny s širším pokrytím. Hĺbkové skenovanie môže trvať niekoľko hodín pre zložité aplikácie.

Čo obsahuje správa Penetrify?

Každá správa obsahuje executive summary, celkové bezpečnostné skóre, nálezy klasifikované podľa závažnosti (Kritické, Vysoké, Stredné, Nízke), podrobné kroky pre reprodukciu a konkrétne odporúčania pre nápravu napísané pre vývojárov – nie pre špecialistov na súlad.

Related articles

CI/CD Penetration Testing: Ako integrovať bezpečnosť do každého nasadenia
Naučte sa, ako integrovať Penetration Testing do vašej CI/CD pipeline. Zahŕňa SAST, DAST, brány kvality a testovanie poháňané umelou inteligenciou bez spomalenia dodávky.
Autonómne OWASP skenovanie zraniteľností: Ako AI nahrádza bezpečnostné testovanie založené na pravidlách
Zistite, ako autonómne skenovanie zraniteľností OWASP využíva AI, aby prekonalo porovnávanie signatúr. Pokrýva OWASP Top 10 2025, agentické testovanie a prečo skenery založené na pravidlách nestačia.
Simulácia viackrokového útočného reťazca: Prečo skenovanie jednej zraniteľnosti nestačí
Zistite, ako simulácia viacstupňových útočných reťazcov odhalí zreťazené exploity, ktoré prehliadajú skenery zraniteľností. Príklady z reálneho sveta, mapovanie MITRE ATT&CK a sprievodca implementáciou.

Explore more

Compare alternatives →Security glossary →CI/CD integration →Security statistics →
Späť na blog