Trumpai
Abu pagal numatytuosius nustatymus užrakina naują lentelę: Appwrite svečiui ir prisijungusiam vartotojui atsakė 401, o Supabase atsako 401/403, kol lentelei nesuteikiate teisių API rolėms. Skirtumas išryškėja, kai taisyklė klaidinga arba užklausa kerta vartotojų ribą. Supabase pusėje svetimos eilutės update grąžino 200 [], o laisva insert politika leido vartotojui prisijungti prie kitos įmonės; Appwrite pusėje kiekvienas bandymas kirsti vartotojų ribą mano teste baigėsi 401 arba 404, o vartotojas negalėjo suteikti savo eilutės niekam, tik sau pačiam arba visiems. Appwrite serverio raktai turi apimtis (scopes); Supabase secret key praleidžia kiekvieną politiką.
Esu Denys, full-stack ir AI inžinierius. Dauguma programų, kurias kuriu ar taisau, veikia ant Supabase, o klientai, dar renkantys backend, klausia, kaip su sauga atrodo Appwrite. Funkcijų sąrašai į tai neatsako, todėl abiem išsiunčiau tas pačias užklausas.
Kaip testavau. Appwrite 2.3.0, savarankiškai (self-hosted) paleistas su Docker 2026 m. spalio 30 d., per REST API kaip svečias, kaip du prisijungę vartotojai A ir B ir su dviem serverio raktais. Supabase pusė yra mano bandymas vietiniame stack (CLI 2.109.1, Postgres 17.6) 2026 m. spalio 24 d. su tomis pačiomis rolėmis, išsamiai aprašytas straipsnyje Supabase RLS policy: pavyzdžiai, išbandyti per API. Abiem atvejais išgalvotos eilutės.
Kaip Appwrite ir Supabase saugo duomenis?
Supabase lenteles saugo Postgres: teisė (grant) nusprendžia, ar API rolės apskritai pasiekia lentelę, o eilučių lygio saugumo (RLS) politikos, rašomos SQL, nusprendžia, kurias eilutes kiekviena užklausa mato ir rašo. Appwrite leidimus laiko šalia duomenų: lentelė turi rolių sąrašą, kurioms leidžiama skaityti, kurti, atnaujinti ar trinti, o įjungus eilučių saugumą (row security) kiekviena eilutė turi savo sąrašą. Pagal Appwrite leidimų dokumentaciją prieiga tik suteikiama, niekada neatimama, ir vartotojui jos reikia lentelės arba eilutės lygiu, ne abiem.
Taigi klausimas ne tas, kuris iš jų turi prieigos kontrolę. Turi abu. Klausimas, kur kiekvienas leidžia suklysti.
Ką daro kiekvienas su nauja lentele?
| Užklausa | Appwrite, leidimai nenustatyti | Supabase, RLS įjungtas, be teisės (spalio 24 d.) |
|---|---|---|
| Svečias sąrašo eilutes | 401 user_unauthorized |
401 permission denied |
| Prisijungęs vartotojas sąrašo | 401 user_unauthorized |
403 permission denied |
| Prisijungęs vartotojas prideda | 401 No permissions provided for action ‘create’ |
netestuota |
Nauja lentelė abiejose uždaryta. Supabase tai nauja: lentelės, sukurtos po 2026 m. spalio 30 d., Data API teisių automatiškai nebegauna; apie tai rašiau straipsnyje spalio 30 d. teisių pakeitimas.
Kas nutinka, kai lentelė atvira visiems?
Du „atviri“ nustatymai nėra tas pats. Appwrite lentelei suteikiau vieną leidimą, read("any"). Supabase įprasta atvira būsena yra išjungtas RLS su paliktomis numatytosiomis teisėmis.
| Svečio užklausa | Appwrite, read("any") |
Supabase, RLS išjungtas, numatytosios teisės (spalio 24 d.) |
|---|---|---|
| Sąrašo eilutes | 200, abi eilutės |
200, abi eilutės |
| Ištrinti eilutę | 401 |
200, abi eilutės ištrintos |
Appwrite „viešas“ reiškia tik skaitymą, nebent suteikiate ir rašymą. Supabase lentelę su išjungtu RLS gali skaityti ir rašyti bet kas, turintis publishable key, todėl „RLS disabled in public“ yra pirmas dalykas, kurį tikrinu.
Kaip veikia „savos eilutės“?
Appwrite įjungiau eilučių saugumą ir lentelei suteikiau vieną leidimą, create("users"). Kai A sukūrė eilutę nenurodydamas leidimų, Appwrite juos nustatė pats: read, update ir delete tik vartotojui A. Supabase tam pačiam tikslui reikia keturių politikų su (select auth.uid()) = user_id.
| Užklausa | Appwrite (spalio 30 d.) | Supabase (spalio 24 d.) |
|---|---|---|
| Svečias sąrašo eilutes | 200, 0 eilučių |
401 (anon be teisės) |
| A sąrašo eilutes | 200, 2 A eilutės |
200, 2 A eilutės |
| A skaito B eilutę | 404 row_not_found |
sąraše negrąžinama |
| A atnaujina B eilutę | 401 |
200 [] |
| A ištrina B eilutę | 401 |
200 [] |
Nė viena sistema neatskleidė B eilutės. Skiriasi atsakymas. Supabase išfiltruoja eilutes, kurias politika slepia, todėl update, kuris nieko neatitiko, yra sėkmė su nuliu eilučių; programa, laikanti „nėra klaidos“ sinonimu „išsaugota“, pasako vartotojui, kad jo pakeitimas pavyko. Appwrite atsisako su klaida, kurios programa negali nepastebėti.
Ar vartotojas gali atiduoti savo duomenis kitam?
Čia dažniausiai suklysta sugeneruotas kodas, todėl išbandžiau abiejose.
| A užklausa | Appwrite | Supabase (spalio 24 d.) |
|---|---|---|
| Sukurti eilutę, skaitomą vartotojo B | 401, Permissions must be one of: any, users, user:A… |
priklauso nuo politikos |
| Pakeisti savo eilutę, kad ją turėtų B | 401, tas pats pranešimas |
403 su pilnu with check; 200 su with check (true) |
| Sukurti eilutę, skaitomą visų | 201, ir svečias ją išvardijo |
tik jei politika leidžia |
Appwrite riboja, ką vartotojas gali suteikti: tik roles, kurias turi pats, t. y. any, users, savo vartotoją ir savo komandas. Tai užblokavo „atiduok mano eilutę kitam“ judesį be jokios mano taisyklės. Bet nesustabdė A paskelbti savo eilutę visiems su read("any"). Jei eilutė niekada neturi būti vieša, leidimų nustatinėti neturėtų klientas; kurkite ją iš serverio funkcijos.
Supabase rezultatas yra toks, kokį sako politika. Pilnas with check atmetė perkėlimą su 403; with check (true), kurį rašo kai kurie generatoriai, leido A perkelti eilutę į B paskyrą.
Ar vartotojas gali prisijungti prie kitos įmonės?
Supabase komandos prieiga paprastai yra memberships lentelė plius politikos. Mano teste insert politika, kurią siūlo daug pamokų, with check (user_id = auth.uid()), leido A pridėti save prie 2 įmonės su 201 Created ir tada skaityti jos algų projektą.
Appwrite komandos (teams) yra įtaisytos. B sukūrė komandą; A bandė prisidėti kaip narys ir kaip savininkas. Abi užklausos grąžino 404 team_not_found: A komandos net nematė. Narystę lemia serveris, o ne jūsų parašyta taisyklė, todėl šio konkretaus nutekėjimo čia nėra. Kad eilutės būtų bendrinamos, vis tiek reikia read("team:…") leidimų, ir juos nustatote patys.
Ką atveria serverio raktas?
| Raktas | Appwrite | Supabase (iš mano anon vs service role testo) |
|---|---|---|
| Pilnas serverio raktas | 200, visos 4 abiejų vartotojų eilutės |
visos 3 eilutės, RLS praleistas |
Raktas su siaura apimtimi (users.read) |
401, missing scope rows.read |
apimčių raktų nėra |
Supabase secret key atitinka service_role, turinčią BYPASSRLS; ką jis atveria, aprašyta straipsnyje anon key vs service role key. Appwrite raktas taip pat ignoruoja eilučių leidimus, bet tik toms apimtims, su kuriomis sukurtas, todėl raktas vartotojams tvarkyti negali skaityti jūsų lentelių. Bet kuris raktas naršyklės pakete yra visiškas viso to, ką jis pasiekia, nutekėjimas.
Dvi smulkesnės Appwrite pastabos: svečias ir prisijungęs vartotojas, paprašę lentelių sąrašo, abu gavo 401 (kvietimui reikia tables.read, kurį turi tik raktai), o read("users") reiškia bet kurią prisijungusią paskyrą, tas pats spąstai kaip auth.uid() is not null Supabase, kai registracija atvira.
Kuris saugesnis?
Nė vienas nėra saugus ar nesaugus pagal numatytuosius nustatymus; abu prasidėjo uždaryti. Skiriasi tai, kur gali slėptis klaida:
| Klausimas | Appwrite | Supabase |
|---|---|---|
| Kur gyvena prieigos taisyklės | Rolių sąrašai lentelėse ir eilutėse | SQL teisės ir politikos |
| Atmesta kito vartotojo rašymo užklausa | Klaida (401 / 404) |
200 su nuliu eilučių update ir delete |
| Eilučių suteikimas kitiems | Tik rolėms, kurias vartotojas turi | Ką leidžia politika |
| Taisyklės pagal stulpelių reikšmes, MFA lygis | Leidimuose jų nėra; reikia serverio kodo | Politikoje, pvz., aal2 jautrioms eilutėms |
| Serverio raktai | Su apimtimis | Secret key praleidžia visas politikas |
Appwrite modelis siauresnis, ir mano teste siauras modelis atmetė kiekvieną vartotojų ribos kirtimą, man nieko nerašant. Supabase modelis yra SQL, todėl gali išreikšti taisykles, kurių Appwrite leidimai negali, pavyzdžiui, „tik su MFA“ ar „tik įmonių, kurioms priklausau, eilutės“, ir gali išreikšti klaidingą taisyklę. Jei jūsų komanda politikų neskaitys, Appwrite numatytieji nustatymai atleidžia daugiau. Jei reikia taisyklių, priklausančių nuo duomenų, Supabase leidžia jas parašyti, ir tada jas reikia testuoti; mano metodas aprašytas straipsnyje kaip testuoju Supabase RLS.
Kaip patikrinti Supabase projektą?
Nemokamas Supabase saugos tikrintuvas skaito jūsų projektą tik skaitymo režimu ir pažymi lenteles su išjungtu RLS, visada teisingas politikas, rašymo politikas svečiams ir teises, suteikiančias daugiau, nei numato politikos. Ką Supabase užtikrina už jus, o ką palieka jums, aprašyta straipsnyje Ar Supabase saugus?. Appwrite atitikmens jame nėra; Appwrite paleiskite aukščiau pateiktas užklausas kaip du vartotojai. Su Firebase tokio paties pobūdžio atakas paleidau straipsnyje Firebase security rules pavyzdžiai.
Apribojimai. Vienas savarankiškai paleistas Appwrite 2.3.0 nešiojamajame kompiuteryje ir vienas vietinis Supabase stack, išbandyti šešių dienų skirtumu, išgalvotos eilutės. Appwrite Cloud gali skirtis nuo self-hosted. Storage, funkcijos, realtime, auth nustatymai ir atitikties sertifikatai čia nelyginami.
Renkatės backend programai su privačiais duomenimis?
Mielai kartu pažiūrėsiu į jūsų prieigos modelį. Be pardavimų kalbų.
Susisiekti