Prejsť na obsah

Appwrite vs Supabase: bezpečnosť, rovnaké útoky na oba

Zobraziť ako MarkdownOtvoriť v ClaudeOtvoriť v ChatGPTOtvoriť v Perplexity

Otázka sa tiež skopíruje. Ak sa chat otvorí prázdny, vložte ju.

TL;DR

Oba v predvolenom stave zamykajú novú tabuľku: Appwrite odpovedal 401 hosťovi aj prihlásenému používateľovi a Supabase odpovedá 401/403, kým tabuľku nepridelíte rolám API. Rozdiel sa ukáže, keď je pravidlo zlé alebo keď požiadavka prechádza medzi používateľmi. Na Supabase vrátila úprava cudzieho riadku 200 [] a príliš voľná politika na vloženie nechala používateľa pripojiť sa do inej firmy; na Appwrite skončil každý pokus naprieč používateľmi v mojom teste ako 401 alebo 404 a používateľ nemohol svoj riadok prideliť nikomu inému než sebe alebo všetkým. Serverové kľúče Appwrite majú scopes; secret key Supabase preskakuje všetky politiky.

Som Denys, full-stack a AI inžinier. Väčšina aplikácií, ktoré stavím alebo opravujem, beží na Supabase, a klienti, ktorí si backend ešte len vyberajú, sa pýtajú, ako si Appwrite stojí v bezpečnosti. Zoznam funkcií na to neodpovie, tak som obom poslal rovnaké požiadavky.

Ako som testoval. Appwrite 2.3.0, self-hosted v Dockeri, 30. októbra 2026, cez jeho REST API ako hosť, ako dvaja prihlásení používatelia A a B a s dvoma serverovými kľúčmi. Strana Supabase je môj test na lokálnom stacku (CLI 2.109.1, Postgres 17.6) z 24. októbra 2026 s rovnakými rolami, podrobne popísaný v článku Príklady politík Supabase RLS. Na oboch vymyslené riadky.

Ako Appwrite a Supabase chránia dáta?

Supabase chráni tabuľky cez Postgres: grant rozhoduje, či sa role API k tabuľke vôbec dostanú, a politiky row level security, písané v SQL, rozhodujú, ktoré riadky každá požiadavka vidí a zapisuje. Appwrite ukladá oprávnenia vedľa dát: tabuľka má zoznam rolí, ktoré smú čítať, vytvárať, upravovať alebo mazať, a so zapnutou row security nesie každý riadok vlastný zoznam. Podľa dokumentácie oprávnení Appwrite sa prístup len udeľuje, nikdy neodopiera, a používateľ ho potrebuje na úrovni tabuľky alebo riadku, nie oboch.

Otázka teda nie je, ktorý z nich má riadenie prístupu. Majú ho oba. Je to v tom, v čom vám každý dovolí urobiť chybu.

Čo robí každý s novou tabuľkou?

Požiadavka Appwrite, bez nastavených oprávnení Supabase, RLS zapnuté, bez grantu (24. 10.)
Hosť vypíše riadky 401 user_unauthorized 401 permission denied
Prihlásený používateľ vypíše riadky 401 user_unauthorized 403 permission denied
Prihlásený používateľ pridá riadok 401 No permissions provided for action ‘create’ netestované

Čerstvá tabuľka je na oboch uzavretá. Na Supabase je to novinka: tabuľky vytvorené po 30. októbri 2026 už automaticky nedostávajú granty Data API, ako som popísal v článku zmena grantov 30. októbra.

Čo sa stane, keď je tabuľka otvorená všetkým?

Dve „otvorené“ nastavenia nie sú to isté. V Appwrite som tabuľke dal jediné oprávnenie, read("any"). Na Supabase je bežný otvorený stav RLS vypnuté s predvolenými grantmi.

Požiadavka hosťa Appwrite, read("any") Supabase, RLS vypnuté, predvolené granty (24. 10.)
Výpis riadkov 200, oba riadky 200, oba riadky
Zmazanie riadku 401 200, oba riadky zmazané

„Verejné“ v Appwrite znamená len čítanie, kým nepridelíte aj zápis. Tabuľku Supabase s vypnutým RLS môže čítať aj zapisovať ktokoľvek s publishable key, preto je „RLS disabled in public“ prvá vec, ktorú kontrolujem.

Ako fungujú „vlastné riadky“ v každom?

V Appwrite som zapol row security a tabuľke dal jediné oprávnenie, create("users"). Keď A vytvoril riadok bez uvedenia oprávnení, Appwrite ich nastavil sám: read, update a delete len pre používateľa A. Na Supabase je rovnaký zámer štyri politiky na (select auth.uid()) = user_id.

Požiadavka Appwrite (30. 10.) Supabase (24. 10.)
Hosť vypíše riadky 200, 0 riadkov 401 (žiadny grant pre anon)
A vypíše riadky 200, 2 riadky A 200, 2 riadky A
A číta riadok B 404 row_not_found vo výpise sa nevráti
A upraví riadok B 401 200 []
A zmaže riadok B 401 200 []
Rovnaká požiadavka, dva backendy. Používateľ A upravuje riadok používateľa B cez REST API oboch. Supabase, politika len pre vlastníka: Používateľ A → úprava riadku B → 200 [] → 0 riadkov, bez chyby; Appwrite, row security zapnuté: Používateľ A → úprava riadku B → 401 → vrátená chyba.
Obrázok 1. Moje testy: lokálny stack Supabase (CLI 2.109.1), 24. októbra 2026; self-hosted Appwrite 2.3.0, 30. októbra 2026.

Ani jeden neprezradil riadok B. Líši sa odpoveď. Supabase filtruje riadky, ktoré politika skrýva, takže úprava, ktorá nič nenašla, je úspech s nulou riadkov; aplikácia, ktorá berie „bez chyby“ ako „uložené“, potom používateľovi povie, že jeho úprava prešla. Appwrite odmietne chybou, ktorú aplikácia nemôže prehliadnuť.

Môže používateľ odovzdať svoje dáta niekomu inému?

Tu generovaný kód chybuje najčastejšie, tak som to skúsil na oboch.

Požiadavka A Appwrite Supabase (24. 10.)
Vytvoriť riadok čitateľný používateľom B 401, Permissions must be one of: any, users, user:A… závisí od politiky
Zmeniť vlastný riadok, aby ho vlastnil B 401, rovnaká správa 403 s úplným with check; 200 s with check (true)
Vytvoriť riadok čitateľný všetkými 201 a hosť ho potom vypísal len ak to politika dovolí

Appwrite obmedzuje, čo môže používateľ udeliť, na roly, ktoré sám drží: any, users, svojho používateľa a svoje tímy. To zablokovalo krok „daj môj riadok niekomu inému“, bez toho aby som napísal jediné pravidlo. Nezabránilo to A zverejniť vlastný riadok všetkým cez read("any"). Ak riadok nesmie byť nikdy verejný, nemal by oprávnenia nastavovať klient; vytvorte ho zo serverovej funkcie.

Na Supabase je výsledok taký, ako hovorí politika. Úplný with check presun odmietol s 403; with check (true), ktoré píšu niektoré generátory, nechalo A presunúť riadok na účet B.

Môže sa používateľ pripojiť do cudzej firmy?

Na Supabase je prístup tímov zvyčajne tabuľka memberships plus politiky. V mojom teste insert politika, ktorú navrhuje množstvo tutoriálov, with check (user_id = auth.uid()), nechala A pridať seba do firmy 2 s 201 Created a potom čítať jej projekt s výplatami.

Appwrite má tímy zabudované. B vytvoril tím; A sa doň skúsil pridať ako člen aj ako vlastník. Obe požiadavky vrátili 404 team_not_found: A tím ani nevidel. O členstve v tíme rozhoduje server, nie pravidlo, ktoré píšete, takže tento konkrétny únik nie je možný. Riadky stále potrebujú oprávnenia read("team:…"), aby sa zdieľali, a tie nastavujete sami.

Čo otvára serverový kľúč?

Kľúč Appwrite Supabase (z môjho testu anon vs service role)
Plný serverový kľúč 200, všetky 4 riadky oboch používateľov všetky 3 riadky, RLS preskočené
Kľúč s úzkym scope (users.read) 401, missing scope rows.read žiadne kľúče so scope

Secret key Supabase zodpovedá roli service_role, ktorá má BYPASSRLS; čo otvára, je v článku anon key vs service role key. Kľúč Appwrite tiež ignoruje oprávnenia riadkov, ale len pre scopes, s ktorými vznikol, takže kľúč pre úlohu spravujúcu používateľov neprečíta vaše tabuľky. Akýkoľvek kľúč v balíku pre prehliadač je plný únik všetkého, k čomu sa dostane.

Dva menšie nálezy v Appwrite: hosť aj prihlásený používateľ, ktorí žiadali o zoznam tabuliek, dostali 401 (volanie vyžaduje tables.read, ktoré majú len kľúče), a read("users") znamená akýkoľvek prihlásený účet, rovnaká pasca ako auth.uid() is not null na Supabase, keď je registrácia otvorená.

Ktorý je bezpečnejší?

Ani jeden nie je v predvolenom stave bezpečný alebo nebezpečný; oba začali uzavreté. Líšia sa tým, kde sa môže chyba skryť:

Otázka Appwrite Supabase
Kde žijú pravidlá prístupu Zoznamy rolí pri tabuľkách a riadkoch SQL granty a politiky
Odopretý zápis naprieč používateľmi Chyba (401 / 404) 200 s nulou riadkov pri update a delete
Prideľovanie riadkov iným Len rolám, ktoré používateľ drží Čokoľvek, čo politika dovolí
Pravidlá podľa hodnôt stĺpcov, úroveň MFA Nie sú v oprávneniach; chce serverový kód V politike, napr. aal2 pre citlivé riadky
Serverové kľúče So scopes Secret key preskakuje všetky politiky

Model Appwrite je užší a v mojom teste odmietol každý trik naprieč používateľmi, bez toho aby som čokoľvek písal. Model Supabase je SQL, takže vyjadrí pravidlá, ktoré oprávnenia Appwrite nevedia, napríklad „len s MFA“ alebo „len riadky firiem, do ktorých patrím“, a vyjadrí aj zlé pravidlo. Ak váš tím politiky čítať nebude, Appwrite v predvolenom stave odpúšťa viac. Ak potrebujete pravidlá závislé od dát, Supabase vám ich dovolí napísať, a potom je nutné ich testovať; metóda, ktorú používam, je v článku ako testovať Supabase RLS.

Ako skontrolovať projekt na Supabase?

Bezplatná Kontrola zabezpečenia Supabase číta váš projekt len na čítanie a označí tabuľky s vypnutým RLS, politiky, ktoré platia vždy, zápisové politiky pre hostí a granty, ktoré dávajú viac, než politiky naznačujú. Čo Supabase rieši za vás a čo necháva na vás, je v článku je Supabase bezpečný?. Pre Appwrite nič také nie je; spustite vyššie uvedené požiadavky ako dvaja používatelia. Pre Firebase som rovnaký druh útokov spustil v článku príklady pravidiel zabezpečenia Firebase.

Limity. Jeden self-hosted Appwrite 2.3.0 na notebooku a jeden lokálny stack Supabase, s odstupom šiestich dní, vymyslené riadky. Appwrite Cloud sa môže líšiť od self-hosted. Storage, funkcie, realtime, nastavenia autentifikácie a certifikáty súladu sa tu neporovnávajú.

Vyberáte backend pre aplikáciu so súkromnými dátami?

Rád sa s vami pozriem na váš model prístupu. Bez ponuky.

Ozvite sa

© 2026 Denys Zaichenko. Pôvodný článok: https://madsalt.tech/sk/blog/appwrite-vs-supabase/