Jede neunte App leakt Supabase-Keys: So passiert es

BBetter Stack
컴퓨터/소프트웨어창업/스타트업AI/미래기술

Transcript

00:00:00Diesen Monat erschien ein Bericht, für den etwa 20.000 Indie-Apps gescannt wurden. Das Ergebnis: Jede neunte
00:00:04veröffentlichte Supabase-Zugangsdaten im Frontend-Code.
00:00:08Das passierte nicht in einem Server-Log oder einem privaten Repo.
00:00:11Die Daten stecken einfach im JavaScript, das jeder Besucher herunterlädt.
00:00:14Und der Punkt ist: Diese Apps wurden nicht gehackt, sie haben das Geheimnis versehentlich mit ausgeliefert.
00:00:18Um das klarzustellen: Manche Keys sollen öffentlich sein.
00:00:21Das Problem ist die Pipeline, denn derselbe Fehler kann einen Key veröffentlichen, der niemals
00:00:25im Browser landen dürfte.
00:00:27Wir veröffentlichen ständig neue Videos.
00:00:28Abonniert also am besten den Kanal.
00:00:35Hier ist die einfache Wahrheit, an der viele scheitern.
00:00:38Wir alle wissen es eigentlich, aber wenn es schnell gehen muss, übersieht man es leicht.
00:00:41Wenn man eine Umgebungsvariable als öffentlich markiert, behandelt das Build-Tool sie so, als gehöre sie
00:00:46in den Browser, und sie landet im Client-Bundle.
00:00:50Next.js nutzt dafür “Next.public
00:00:56“public”.
00:00:57“Next” ist kein Sicherheitssiegel, sondern wortwörtlich das Versandetikett.
00:01:01Das wissen wir jetzt, aber hier kommt der Teil speziell zu Supabase.
00:01:04Manche Keys sind für die Öffentlichkeit gedacht, wie Anon- oder Publishable-Keys, andere sind privat,
00:01:10wie die Service-Role oder Secret-Keys.
00:01:12Wenn ein privater Key im Browser landet, nun ja, ihr könnt euch sicher denken, was dann passiert.
00:01:17Row-Level Security (RLS) wird euch in diesem Fall nicht retten.
00:01:20In der Supabase-Doku steht klar, dass Service-Keys die RLS umgehen können.
00:01:24Wenn dieser Key also in eurem Frontend ist, spielt eure ganze Policy-Arbeit keine Rolle mehr.
00:01:29Ich zeige euch jetzt anhand meiner Sandbox genau, wie das passiert ist.
00:01:33Zuerst habe ich eine einfache CRUD-App mit Next.js gebaut und mein Supabase-Projekt verknüpft.
00:01:38Hier ist meine .env-Datei, und hier liegt der Fehler.
00:01:41Ich habe einen Key in einer Variable mit dem Präfix “public” gespeichert.
00:01:45Dieser Key ist zwar öffentlich, soll also sichtbar sein.
00:01:48Das eigentliche Problem ist, dass über denselben Next.public-Pfad versehentlich auch ein privater Key landen kann.
00:01:53Ich habe “npm run build” ausgeführt, um die App zu bauen, und sie dann gestartet.
00:01:59Hier bin ich in Chrome.
00:02:00Ich füge mal eben ein paar Testdaten in unsere Datenbank bzw. CRUD-App ein.
00:02:05Okay, jetzt öffne ich das kompilierte JavaScript-Bundle und suche danach.
00:02:10Da ist er.
00:02:12Die URL und der Key stehen buchstäblich in der Datei, die eure Nutzer gerade in ihren
00:02:18Browser geladen haben.
00:02:19Und beachtet, was NICHT passiert ist.
00:02:21Niemand ist irgendwo eingebrochen.
00:02:22Ich habe das einfach so gefunden.
00:02:24Es wurde keine Sicherheitslücke ausgenutzt.
00:02:25Das ist bloß das Auslesen dessen, was die App bereits ins öffentliche Internet geschickt hat.
00:02:29Wenn ich es sehen kann, kann es jeder sehen.
00:02:32Dev-Tools öffnen, die JavaScript-Dateien anschauen und danach suchen.
00:02:35Mehr braucht es nicht.
00:02:36Falls euer Plan also lautet: “Es wird schon niemand nachschauen” – das Internet ist voll von Leuten und Bots,
00:02:41deren einziger Job es ist, genau nach solchen Dingen zu suchen.
00:02:44Hier ist die Lösung, die wirklich funktioniert.
00:02:47Der Browser sollte ausschließlich eure API aufrufen.
00:02:50Eure API läuft serverseitig.
00:02:52Dort gehören private Keys hin.
00:02:54Verschiebt die private Operation in eine API-Route oder Server-Funktion.
00:02:58Der Client ruft euren Endpunkt auf, dieser ruft Supabase auf. Dann baut ihr das Projekt neu und prüft
00:03:03das Bundle noch einmal.
00:03:04Wenn der Key aus dem Bundle verschwunden ist, habt ihr es gefixt. Aber hört dort noch nicht auf,
00:03:09denn ihr könnt noch mehr tun.
00:03:11Stellt sicher, dass Row-Level Security für Tabellen mit Nutzerkontakt aktiviert ist und dass eure Policies
00:03:16genau das tun, was ihr beabsichtigt.
00:03:18Investiert auch Zeit in Tests.
00:03:19Ich finde, das wird oft zu oberflächlich behandelt.
00:03:21Um zu verhindern, dass der Fehler wiederkehrt: Viele fixen das einmal und führen es später
00:03:26unter Zeitdruck wieder ein.
00:03:28Baut also Sicherheitsvorkehrungen ein. Beginnt mit Secret-Scanning in der CI, damit Builds scheitern,
00:03:34wenn ein Key auftaucht, wo er nicht hingehört.
00:03:36Führt eine PR-Regel ein, nach der alles mit “Next public” oder “Vite” standardmäßig als öffentlich gilt –
00:03:41denn das ist es ja auch.
00:03:42Und schließlich: Nutzt Key-Rotation.
00:03:43Sobald ihr auch nur den leisesten Verdacht habt, dass Keys exponiert wurden, tauscht sie aus.
00:03:47Das ist besser, als erst mal abzuwarten, was in den nächsten Tagen passiert.
00:03:50Das könnt ihr sofort ausprobieren:
00:03:52Baut eure App genau so, wie ihr sie ausliefert.
00:03:55Durchsucht den Output nach Supabase-JWTs, Service-Secrets und allem, was nach einem Token aussieht.
00:04:01Wenn ihr etwas Privates findet, betrachtet es als kompromittiert – schließlich habt ihr es ja gefunden.
00:04:05Tauscht den Key aus und stellt eure Logik auf serverseitig um.
00:04:08Wenn ihr euch nur einen Satz aus diesem Video merkt, dann diesen:
00:04:11Wenn es im Bundle ist, ist es öffentlich.
00:04:13Wir sehen uns im nächsten Video.

Key Takeaway

Alles, was im JavaScript-Bundle des Frontends landet, ist öffentlich zugänglich, weshalb private Keys strikt auf der Serverseite verbleiben müssen.

Highlights

Etwa 11% (jede neunte) der untersuchten Indie-Apps leaken versehentlich Supabase-Zugangsdaten im Frontend-Code.

Das Problem liegt oft bei Build-Tools wie Next.js

Timeline

Das Ausmaß des Datenlecks

Ein aktueller Bericht zeigt auf, dass bei einem Scan von 20.000 Indie-Apps jede neunte Anwendung sensible Supabase-Daten preisgibt. Diese Informationen befinden sich direkt im JavaScript-Code, der von jedem Besucher heruntergeladen werden kann. Es handelt sich dabei nicht um einen aktiven Hack, sondern um ein versehentliches Mitliefern von Geheimnissen während des Build-Prozesses. Der Sprecher betont, dass die Pipeline das eigentliche Problem darstellt, da sie fälschlicherweise interne Keys als öffentliche Daten behandelt. Dieser Abschnitt verdeutlicht, dass das Risiko in der Infrastruktur der App-Veröffentlichung verwurzelt ist.

Die Falle der Umgebungsvariablen

Viele Entwickler scheitern an der Handhabung von Umgebungsvariablen unter Zeitdruck. Build-Tools wie Next.js verwenden Präfixe wie "NEXT_PUBLIC", um Variablen explizit für den Browser freizugeben. Der Sprecher erklärt treffend, dass solche Präfixe kein Sicherheitssiegel, sondern ein Versandetikett für das Client-Bundle sind. Speziell bei Supabase muss zwischen öffentlichen Anon-Keys und privaten Service-Role-Keys unterschieden werden. Werden diese Kategorien verwechselt, landen hochsensible Zugriffsrechte direkt im Browser der Endnutzer.

Warum RLS bei Service-Keys versagt

In diesem Teil wird erklärt, warum die Row-Level Security (RLS) keinen Schutz bietet, wenn der falsche Key exponiert wird. Laut der Supabase-Dokumentation sind Service-Keys so konzipiert, dass sie sämtliche Sicherheits-Policies umgehen können. Wenn ein solcher Key im Frontend landet, ist die gesamte Arbeit an den Sicherheitsregeln hinfällig, da der Zugriff administrativ erfolgt. Dies stellt einen kritischen Punkt für die Datenbankintegrität und den Datenschutz dar. Der Sprecher warnt davor, sich auf RLS zu verlassen, wenn die Key-Verwaltung fehlerhaft ist.

Live-Demo der Sicherheitslücke

Anhand einer Sandbox-Umgebung demonstriert der Sprecher, wie eine einfache Next.js CRUD-App durch einen Fehler in der .env-Datei kompromittiert wird. Nach dem Ausführen von "npm run build" zeigt er im Chrome-Browser, dass die privaten Zugangsdaten im kompilierten JavaScript-Bundle im Klartext auffindbar sind. Er betont, dass keine speziellen Tools oder Hacker-Skills nötig sind; die Dev-Tools des Browsers reichen völlig aus. Bots scannen das Internet permanent nach genau diesen Mustern, um Daten abzugreifen. Es wird klargestellt: Was im Bundle steht, gehört dem Internet.

Lösungen und Präventionsstrategien

Die wirksamste Lösung ist die konsequente Trennung von Client und Server durch API-Routen. Private Keys dürfen nur in serverseitigen Funktionen existieren, während der Browser lediglich einen Endpunkt aufruft. Zusätzlich sollten Entwickler auf Secret-Scanning in ihrer CI-Pipeline setzen, um fehlerhafte Builds sofort zu stoppen. PR-Reviews sollten kritisch prüfen, ob Variablen mit öffentlichen Präfixen wirklich für das Frontend bestimmt sind. Schließlich wird die Key-Rotation als notwendiges Mittel empfohlen, falls ein Verdacht auf eine Kompromittierung besteht.

Fazit und Checkliste

Zum Abschluss gibt der Sprecher eine praktische Handlungsanweisung für alle Entwickler. Man sollte die eigene App so bauen, wie sie ausgeliefert wird, und den Output manuell nach Tokens oder JWTs durchsuchen. Jeder gefundene private Key muss sofort als kompromittiert betrachtet und ausgetauscht werden. Die Umstellung der Logik auf serverseitige Prozesse ist danach unumgänglich für die Sicherheit. Der wichtigste Merksatz des gesamten Videos lautet: "Wenn es im Bundle ist, ist es öffentlich".

Community Posts

No posts yet. Be the first to write about this video!

Write about this video