---
title: "Appwrite vs Supabase: bezpečnosť, rovnaké útoky na oba"
description: "Rovnaké útoky na prístup som pustil na Appwrite 2.3.0 a lokálny Supabase. Oba zamykajú nové tabuľky; líšia sa tým, ako zlyhá chyba a čo otvorí kľúč."
url: "https://madsalt.tech/sk/blog/appwrite-vs-supabase/"
author: "Denys Zaichenko"
author_url: "https://madsalt.tech/sk/about/"
language: "sk"
published: 2026-10-30
---

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

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

## Č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.](https://madsalt.tech/charts/sk/appwrite-vs-supabase.svg)

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

## Ako skontrolovať projekt na Supabase?

Bezplatná [Kontrola zabezpečenia Supabase](https://madsalt.tech/sk/tools/supabase-security-check/) čí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ý?](https://madsalt.tech/sk/blog/is-supabase-secure/). 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](https://madsalt.tech/sk/blog/firebase-security-rules-examples/).

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