Sicherheit je Werkzeug

Supabase: Ist deine Datenbank ohne Anmeldung lesbar?

Supabase ist standardmäßig so gebaut, dass dein Frontend direkt mit der Datenbank spricht. Der dafür nötige anon-Schlüssel ist öffentlich — das ist Absicht. Abgesichert wird der Zugriff nicht durch den Schlüssel, sondern durch Row Level Security: Regeln in der Datenbank, die je Zeile entscheiden, wer sie sehen darf. Fehlen diese Regeln, kann jeder, der deine Seite öffnet, die komplette Tabelle herunterladen. Das ist der häufigste schwerwiegende Fehler in KI-gebauten Apps, und er ist von außen prüfbar.

Der Scan ist kostenlos und dauert etwa zwanzig Sekunden. Du siehst sofort, wie viele Befunde es gibt und wie schwer sie wiegen.

Eigene App kostenlos scannen

Warum der öffentliche Schlüssel kein Problem ist — und wann doch

Supabase kennt zwei Schlüssel. Der `anon`-Schlüssel gehört ins Frontend; er identifiziert dein Projekt, nicht einen Nutzer. Der `service_role`-Schlüssel umgeht alle Regeln und gehört ausschließlich auf einen Server.

Der anon-Schlüssel ist also nicht geheim und muss es nicht sein. Er wird erst gefährlich, wenn keine Regel prüft, was der Fragende sehen darf. Dann ist er kein Ausweis mehr, sondern ein Generalschlüssel.

Ein `service_role`-Schlüssel im Frontend ist dagegen immer ein kritischer Befund — er hebt jede Regel auf.

In zwei Minuten selbst prüfen

Öffne deine App, drücke F12, wechsle auf „Netzwerk“ und lade die Seite neu. Filtere nach `supabase`. Du siehst Anfragen an eine Adresse der Form `https://<projekt>.supabase.co/rest/v1/<tabelle>`.

Kopiere eine davon mitsamt dem `apikey`-Wert und öffne sie in einem privaten Fenster, in dem du nicht angemeldet bist. Bekommst du Datensätze zurück, ist die Tabelle ohne Anmeldung lesbar.

Wichtig ist der abgemeldete Zustand. Im eigenen, angemeldeten Browser sieht alles richtig aus — das ist der Grund, warum dieser Fehler so lange unbemerkt bleibt.

Die Regeln richtig setzen

Zwei Schritte, und beide gehören zusammen. `ENABLE ROW LEVEL SECURITY` sperrt zunächst alles — auch deine eigene App. Erst die Policies öffnen wieder gezielt.

Wer nur den ersten Schritt macht, hat eine funktionierende Sperre und eine kaputte App. Wer nur den zweiten macht, hat gar nichts: Ohne aktivierte RLS werden Policies nicht ausgewertet.

ALTER TABLE profiles ENABLE ROW LEVEL SECURITY;

-- Lesen: nur die eigene Zeile
CREATE POLICY "Eigenes Profil lesen"
  ON profiles FOR SELECT
  USING (auth.uid() = id);

-- Ändern: nur die eigene Zeile
CREATE POLICY "Eigenes Profil ändern"
  ON profiles FOR UPDATE
  USING (auth.uid() = id)
  WITH CHECK (auth.uid() = id);

-- Anlegen: nur mit der eigenen Kennung
CREATE POLICY "Eigenes Profil anlegen"
  ON profiles FOR INSERT
  WITH CHECK (auth.uid() = id);

Die drei häufigsten Fehler bei den Policies

Erstens: `USING (true)`. Das ist eine Regel, die alles erlaubt — häufig als Zwischenschritt gesetzt, um weiterzukommen, und dann vergessen. Für die Datenbank ist das dasselbe wie keine Regel.

Zweitens: `USING` ohne `WITH CHECK` bei `UPDATE`. `USING` entscheidet, welche Zeilen jemand ändern darf; `WITH CHECK` entscheidet, wie sie danach aussehen dürfen. Ohne `WITH CHECK` kann jemand seine eigene Zeile so ändern, dass sie jemand anderem gehört.

Drittens: Regeln nur auf einer Tabelle. RLS gilt je Tabelle. Die abgesicherte `profiles`-Tabelle nützt wenig, wenn `orders` mit denselben Personendaten offen ist.

Nach der Änderung nachprüfen

Wiederhole die Prüfung von oben im abgemeldeten Fenster. Jetzt sollte eine leere Liste oder ein Fehler zurückkommen — nicht deine Daten.

Danach die App im angemeldeten Zustand durchklicken: Sieht ein Nutzer noch seine eigenen Daten? Zu strenge Regeln fallen sonst erst dem ersten Kunden auf.

Das prüfen wir automatisch

  • Row Level Security je Tabelle (Deep-Scan)
  • service_role-Schlüssel im Frontend
  • Erreichbare REST-Endpunkte ohne Anmeldung

Häufige Fragen

Ist der Supabase-anon-Schlüssel geheim?
Nein, und er muss es auch nicht sein. Er identifiziert dein Projekt gegenüber Supabase, nicht einen Nutzer. Die Absicherung passiert über Row Level Security in der Datenbank. Der `service_role`-Schlüssel ist dagegen geheim und gehört niemals ins Frontend.
Was bedeutet „Row Level Security ist nicht aktiviert“?
Dass die Datenbank bei einer Anfrage nicht prüft, wer fragt, sondern die Zeilen einfach ausliefert. In Verbindung mit dem öffentlichen anon-Schlüssel aus deinem Frontend heißt das: Jeder Besucher kann die vollständige Tabelle herunterladen.
Muss ich für jede Tabelle eigene Regeln schreiben?
Ja. Row Level Security gilt je Tabelle, und die Policies müssen zur jeweiligen Datenstruktur passen. Eine abgesicherte Nutzertabelle hilft nicht, wenn die Bestelltabelle daneben offen ist.
Ist eine offene Supabase-Tabelle ein meldepflichtiges Datenleck?
Wenn darin Personendaten stehen und sie tatsächlich öffentlich abrufbar waren, ist das nach Art. 33 DSGVO in der Regel ein meldepflichtiger Vorfall — mit einer Frist von 72 Stunden gegenüber der Aufsichtsbehörde. Das ist keine Rechtsberatung; im Ernstfall gehört das anwaltlich geprüft.