Was es ist und warum es zählt
Viele Apps, die mit Claude Code gebaut werden, nutzen ein fertiges Backend, etwa Supabase oder Firebase. Das ist praktisch: Die App spricht direkt mit der Datenbank, aus dem Browser oder vom Handy, ohne eigenen Server dazwischen.
Dafür trägt die App zwei Dinge mit sich: die Adresse des Projekts und einen öffentlichen Schlüssel. Jeder, der deine App öffnet, kann sie sehen, ein Blick auf die Anfragen im Browser reicht. Und das ist in Ordnung: Dieser Schlüssel gehört genau dorthin. Er ist kein Passwort, er sagt nur „diese Anfrage kommt von meiner App“.
Entscheidend ist, was hinter der Tür liegt. Wer was lesen darf, entscheidet nicht der Schlüssel, sondern die Regeln in der Datenbank. Bei Supabase heißen sie Row Level Security (Sicherheit auf Zeilenebene), bei Firebase Sicherheitsregeln. Einfach gesagt: Für jede Tabelle legst du fest, wer welche Zeilen lesen, hinzufügen, ändern und löschen darf. Zum Beispiel: „Jeder Nutzer sieht nur seine eigenen Bestellungen.“
Fehlen diese Regeln oder sind sie zu locker geschrieben, öffnet der öffentliche Schlüssel alles. Wer Adresse und Schlüssel aus dem Browser kopiert, kann die Tabellen lesen: E-Mails, Namen, Nachrichten, alles, was du dort gespeichert hast. Manchmal sie sogar ändern. Dafür muss man kein Hacker sein: Eine Zeile im Terminal reicht.
Claude legt die Tabellen an und die App funktioniert, denn bei dir kommen die Daten an, solange du eingeloggt bist. Ob sie auch bei Leuten ganz ohne Konto ankommen, siehst du beim Benutzen der App nicht. Du siehst es nur, wenn du es testest.
Vor allem: nur bei deiner eigenen App
Diesen Test machst du bei deinem eigenen Projekt, mit deinen Daten oder mit Testnutzern. Niemals bei Apps oder Datenbanken anderer, auch nicht „nur mal schauen“: Ohne Erlaubnis in ein System einzudringen kann eine Straftat sein, in Italien wie in vielen anderen Ländern. Wenn du glaubst, dass die App von jemand anderem offen ist, probier es nicht aus: Schreib den Betreibern.
1. Der Test, in zwei Minuten
Drei Teile: Der erste findet den Schlüssel, der zweite schaut, was jemand ohne Login sieht, der dritte, ob ein Nutzer die Daten eines anderen liest. Ich beschreibe sie für Supabase; für Firebase schau weiter unten.
a. Den Schlüssel finden
- Öffne deine App im Browser, ohne dich einzuloggen.
- Rechtsklick > Untersuchen > Tab Netzwerk (Network), dann die Seite neu laden.
- Such die Anfragen an die Datenbank. Bei Supabase sind das Adressen, die auf .supabase.co enden.
- Klick eine Anfrage an: Dort siehst du die Adresse des Projekts und den öffentlichen Schlüssel (publishable oder anon).
Wenn du keine Anfragen an die Datenbank findest, geh auf eine Seite, die Daten lädt, und schau noch einmal.
b. Versuch, ohne Login zu lesen
Ohne Login öffnest du ein Terminal und führst diese Zeile aus. Setz dein Projekt, deinen öffentlichen Schlüssel und den Namen einer deiner Tabellen ein:
curl "https://DEIN-PROJEKT.supabase.co/rest/v1/TABELLENNAME?select=*" -H "apikey: OEFFENTLICHER_SCHLUESSEL"
Kommen Nutzerzeilen zurück, ist die Tür offen. Kommt eine leere Liste, [], oder ein Berechtigungsfehler, antwortet diese Tabelle nicht jedem, der vorbeikommt. Zwei Dinge beachten: Prüf, ob in der Tabelle wirklich Daten stehen, sonst sagt dir eine leere Liste nichts. Und wiederhol es für jede Tabelle, nicht nur für eine.
c. Als Nutzer A testen
Leg zwei Testnutzer an, A und B, und lass jeden etwas speichern: ein Profil, eine Notiz, eine Bestellung. Dann logg dich als A ein und kopier das Zugriffstoken: Du findest es im Tab Netzwerk, im Header Authorization der Anfragen nach dem Login. Dann führ aus:
curl "https://DEIN-PROJEKT.supabase.co/rest/v1/TABELLENNAME?select=*" -H "apikey: OEFFENTLICHER_SCHLUESSEL" -H "Authorization: Bearer TOKEN_VON_A"
Die beiden Header haben unterschiedliche Aufgaben. Der öffentliche Schlüssel gehört immer in apikey. Authorization: Bearer trägt nur das Zugriffstoken eines eingeloggten Nutzers, nie den öffentlichen und nie den geheimen Schlüssel. Deshalb hat die erste Zeile nur apikey: Dort gibt es keinen Nutzer.
Wenn die Zeilen von B dabei sind, liest A bei B mit. Das ist das Loch, das man am leichtesten übersieht: Die Tür ist für Nicht-Eingeloggte zu, aber wer drin ist, sieht alles. Behandle das Token von A wie ein Passwort: Damit bist du A. Nutz es nur für den Test und füg es nirgendwo ein.
Wenn du es nicht von Hand machen willst
Bitte Claude darum, in deinem Projekt. Es stellt die Anfragen für dich:
Mach du den Test: Versuch mit dem öffentlichen Schlüssel und ohne Login, jede Tabelle zu lesen; prüf dann mit zwei Testnutzern, ob A die Daten von B sieht. Sag mir Tabelle für Tabelle, was offen ist. Ändere nichts.
Wenn Claude Code dich um Erlaubnis bittet, einen Befehl auszuführen, lies, was es vorhat, bevor du Ja sagst. „Ändere nichts“ ist genau dafür da: Der Test liest, er schreibt nicht.
2. Der Prompt, der es behebt
Wenn du weißt, was offen ist, mach es zu. Das ist der Prompt, den ich benutze:
Jeder Nutzer sieht nur seine eigenen Zeilen. Aktiviere Row Level Security auf jeder Tabelle und schreib die Regeln: Lesen, Einfügen, Ändern und Löschen nur bei den Zeilen des eingeloggten Nutzers. Wirklich öffentliche Tabellen (z. B. ein Katalog) nur lesend. Prüf auch die Views, die RPC-Funktionen und die Storage-Buckets. Liste mir alles mit der Regel auf, die du gesetzt hast, dann mach den Test noch einmal und zeig mir, dass A B nicht mehr sieht.
Die Wörter sind mit Absicht gewählt. „Lesen, Einfügen, Ändern und Löschen“, weil die Regeln bei Supabase pro Operation geschrieben werden: Wenn du nur das Lesen sperrst, kann jemand immer noch schreiben oder löschen. „Die Views, die RPC-Funktionen und die Storage-Buckets“, weil Daten nicht nur aus Tabellen kommen. Bei Supabase überspringt eine View standardmäßig die Regeln der Tabellen, die sie liest; eine Funktion kann so geschrieben sein, dass sie sie überspringt; hochgeladene Dateien haben ganz eigene Regeln. Und „mach den Test noch einmal“, weil du eine Regel prüfst, indem du sie ausprobierst, nicht indem du sie liest.
3. Zwei Dinge, die du wissen solltest
Lieber eine geschlossene Tür
Bei Supabase kommt mit aktiver Row Level Security und ohne geschriebene Regeln über den öffentlichen Schlüssel nichts durch: lieber eine geschlossene Tür als eine offene. Dann öffnest du nur, was nötig ist. Wenn nach dem Fix ein Bildschirm keine Daten mehr lädt, schalte die Sicherheit nicht ab: Es fehlt eine Regel. Bitte Claude, genau diese hinzuzufügen, mehr nicht.
Die zwei Schlüssel
- Der öffentliche Schlüssel (publishable, oder anon in älteren Projekten) darf in der App und im Browser stehen. Allein öffnet er nur, was die Regeln erlauben.
- Der geheime Schlüssel (secret oder service_role) überspringt alle Regeln: nur auf dem Server, nie in der App, nie auf GitHub.
Wenn der geheime Schlüssel in der App oder in einem Repository gelandet ist, betrachte ihn als verbrannt. Erstell im Supabase-Dashboard einen neuen, setz ihn überall dort ein, wo der alte gebraucht wurde, und lösch oder deaktivier den alten erst danach. Ihn aus dem Code zu entfernen reicht nicht: Er bleibt in der Historie und bei allen, die ihn schon gesehen haben.
Such im Code der App und in allem, was im Browser oder in der veröffentlichten App landet, nach dem geheimen Supabase-Schlüssel (secret oder service_role). Prüf auch die Git-Historie. Sag mir, wo du ihn findest. Ändere nichts.
Wenn du Firebase nutzt
Gleiches Prinzip, dort heißen sie Sicherheitsregeln. Auch bei Firebase ist der Schlüssel der App kein Geheimnis: Er identifiziert das Projekt. Was die Daten schützt, sind die Regeln.
Die Regel, nach der du suchst, ist die, die alle durchlässt, etwa allow read, write: if true. Die Firebase-Dokumentation sagt, man soll sie nie in Produktion verwenden. Stattdessen brauchst du Regeln, die prüfen, wer eingeloggt ist und wem das Dokument gehört.
Lies die Firebase-Sicherheitsregeln meines Projekts. Sag mir, welche Sammlungen jemand ohne Login lesen oder schreiben kann und ob ein Nutzer die Dokumente eines anderen lesen kann. Schlag mir dann Regeln vor, bei denen jeder Nutzer nur seine eigenen Daten sieht und ändert. Veröffentliche nichts, bis ich es dir sage.
Häufige Fehler
- Nur eine Tabelle testen. Jede Tabelle hat ihre eigenen Regeln: Teste sie alle.
- Nur das Lesen sperren. Schreib die Regeln auch für Einfügen, Ändern und Löschen.
- Die Tabellen abschließen und Views, Funktionen und Dateien vergessen. Prüf auch die, mit demselben Test.
- Eine Regel, die jeden Eingeloggten alles lesen lässt. Die richtige Prüfung ist, wem die Zeile gehört, nicht ob man eingeloggt ist.
- Die Sicherheit abschalten, wenn ein Bildschirm nicht mehr funktioniert. Füg die fehlende Regel hinzu, statt wieder alles zu öffnen.
- Den geheimen Schlüssel in die App oder ins Repository packen. Nutz ihn nur auf dem Server und ersetz ihn, wenn er rausgekommen ist.
Checkliste
- Ich habe den Test ohne Login bei jeder Tabelle gemacht.
- Mit zwei Testnutzern sieht A die Daten von B nicht.
- Jede Tabelle hat Regeln für Lesen, Einfügen, Ändern und Löschen.
- Ich habe auch Views, RPC-Funktionen und Storage-Buckets geprüft.
- Öffentliche Tabellen sind nur lesbar.
- Der geheime Schlüssel liegt nur auf dem Server.
- Ich habe den Test nach dem Fix wiederholt.
Häufige Fragen
Darf ich diesen Test aus Neugier bei der App von jemand anderem machen?
Nein. Nur bei deiner eigenen App. Ohne Erlaubnis Daten aus einem System zu lesen kann eine Straftat sein, auch wenn die Tür offen steht. Wenn du ein Problem vermutest, sag den Betreibern der App Bescheid.
Nach dem Fix lädt die App manche Daten nicht mehr. Was habe ich falsch gemacht?
Wahrscheinlich nichts: Die Tür ist jetzt zu und für diesen Fall fehlt eine Regel. Sag Claude, welcher Bildschirm nicht lädt, und bitte um die engste Regel, die ausreicht, dann mach den Test mit A und B noch einmal.
Muss ich ihn ab und zu wiederholen?
Jedes Mal, wenn du eine Tabelle hinzufügst oder änderst, wer was sehen darf. Die Regeln gelten Tabelle für Tabelle, und eine neue Tabelle kann ohne entstehen.