---
title: "Appwrite vs Supabase sauga: tos pačios atakos abiem"
description: "Tas pačias prieigos atakas paleidau ant Appwrite 2.3.0 ir vietinio Supabase. Abu užrakina naujas lenteles; skiriasi klaidos baigtis ir ką atveria raktas."
url: "https://madsalt.tech/lt/blog/appwrite-vs-supabase/"
author: "Denys Zaichenko"
author_url: "https://madsalt.tech/lt/about/"
language: "lt"
published: 2026-10-30
---

# Appwrite vs Supabase sauga: tos pačios atakos abiem

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](https://madsalt.tech/lt/blog/supabase-rls-policy-examples/). 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ą](https://appwrite.io/docs/products/databases/tablesdb/permissions) 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](https://madsalt.tech/lt/blog/supabase-october-30-grant-change/).

## 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 []`                 |

![Ta pati užklausa, du backend. Vartotojas A redaguoja vartotojo B eilutę per kiekvieno REST API. Supabase, tik savininko politika: Vartotojas A → keičia B eilutę → 200 \[\] → 0 eilučių, be klaidos; Appwrite, eilučių saugumas įjungtas: Vartotojas A → keičia B eilutę → 401 → grąžinta klaida.](https://madsalt.tech/charts/lt/appwrite-vs-supabase.svg)

*1 pav. Mano testai: vietinis Supabase stack (CLI 2.109.1), 2026 m. spalio 24 d.; self-hosted Appwrite 2.3.0, 2026 m. spalio 30 d.*

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](https://madsalt.tech/lt/blog/supabase-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](https://madsalt.tech/lt/blog/how-to-test-supabase-rls/).

## Kaip patikrinti Supabase projektą?

Nemokamas [Supabase saugos tikrintuvas](https://madsalt.tech/lt/tools/supabase-security-check/) 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?](https://madsalt.tech/lt/blog/is-supabase-secure/). 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](https://madsalt.tech/lt/blog/firebase-security-rules-examples/).

**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](https://madsalt.tech/lt/#contact)
