[{"data":1,"prerenderedAt":464},["ShallowReactive",2],{"blog-de-which-api-keys-are-safe-in-your-frontend":3},{"id":4,"title":5,"body":6,"category":420,"cover":421,"coverAlt":421,"description":422,"draft":423,"extension":424,"faq":425,"image":441,"keywords":442,"meta":451,"navigation":452,"ogTitle":453,"path":454,"published":455,"seo":456,"stem":457,"tldr":458,"updated":462,"__hash__":463},"blog_de\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend.md","Welche API-Schlüssel im Frontend sicher sind, und welche nicht",{"type":7,"value":8,"toc":410},"minimark",[9,13,21,26,29,32,48,51,55,58,61,64,73,79,83,205,208,227,231,253,259,275,286,289,299,304,314,321,325,334,337,344,347,354,358,394,402],[10,11,12],"p",{},"Wer seine App mit Lovable, Bolt, v0, Cursor oder Replit gebaut hat, erlebt\nfrüher oder später Folgendes: Jemand öffnet die Seite, drückt F12 und teilt mit,\nder API-Schlüssel sei „offengelegt\". Über eine App, deren Code man selbst nicht\nlesen kann, ist das eine beunruhigende Nachricht.",[10,14,15,16,20],{},"Hier ist der Punkt, den Anleitung um Anleitung falsch darstellt: ",[17,18,19],"strong",{},"Manche dieser\nSchlüssel gehören genau dorthin."," Jeden sichtbaren Schlüssel als Sicherheitsleck\nzu behandeln führt entweder zu Panik ohne Anlass oder, deutlich schlimmer,\ndazu, die Warnung irgendwann zu ignorieren. Auch an dem Tag, an dem sie zählt.",[22,23,25],"h2",{"id":24},"ist-es-schlimm-dass-mein-api-schlüssel-sichtbar-ist","Ist es schlimm, dass mein API-Schlüssel sichtbar ist?",[10,27,28],{},"Meistens nicht. Es hängt vollständig davon ab, um welchen Schlüssel es geht.",[10,30,31],{},"Jeder Dienst, der mit einem Browser spricht, vergibt zwei verschiedene Arten von\nZugangsdaten. Die eine ist eine Adresse. Die andere ist ein Schlüsselbund zum\nGebäude. Beide heißen „API-Schlüssel\", und das ist der größte Teil der\nVerwirrung.",[10,33,34,35,38,39,42,43,47],{},"Eine ",[17,36,37],{},"Adresse"," darf veröffentlicht werden. Sie sagt nur, zu welchem Projekt\neine Anfrage gehört; die eigentliche Rechteprüfung passiert woanders. Ein\n",[17,40,41],{},"Schlüsselbund"," darf das nicht, denn er ",[44,45,46],"em",{},"ist"," die Rechteprüfung: Wer ihn hat,\ndarf alles, was er erlaubt, von überall.",[10,49,50],{},"Deine App braucht die Adresse im Browser, um überhaupt zu funktionieren. Den\nSchlüsselbund sollte sie dort nie brauchen.",[22,52,54],{"id":53},"warum-deine-app-überhaupt-schlüssel-an-den-browser-schickt","Warum deine App überhaupt Schlüssel an den Browser schickt",[10,56,57],{},"Weil die Anfrage vom Browser deiner Besucherin kommt, nicht von deinem Server.",[10,59,60],{},"Wenn deine App die Bestellungen deiner Nutzer lädt, geht diese Anfrage direkt\nvom Browser der Besucherin an deinen Datenbankanbieter. Sie muss sagen, zu\nwelchem Projekt sie gehört, und diese Kennung muss in der Seite stehen, weil die\nAnfrage genau von dort gestellt wird.",[10,62,63],{},"Es gibt keine Variante, in der diese Kennung geheim bleibt. Sie erreicht jede\nBesucherin, so ist es gedacht. Und genau deshalb teilen Anbieter ihre\nZugangsdaten in zwei Sorten: Sie wissen, dass eine davon öffentlich wird, also\nhaben sie diese harmlos gemacht.",[10,65,66,67,72],{},"Die Sicherheit entsteht nicht dadurch, die Adresse zu verstecken. Sie entsteht\ndurch die Regeln am anderen Ende: bei Supabase durch Row Level Security, die\nZeile für Zeile entscheidet, wer was sehen darf. Diese Regeln sind das, was zu\nprüfen sich lohnt, und\n",[68,69,71],"a",{"href":70},"\u002Fblog\u002Fsupabase-rls-on-but-table-still-public","sie anzuschalten ist nicht dasselbe wie geschützt zu sein",".",[74,75],"diagram",{"alt":76,"caption":77,"src":78},"Zwei Wege zur selben Tabelle. Der anon-Schlüssel wird an der Row-Level-Security-Sperre gestoppt und erreicht nur die zwei Zeilen, die die Regeln erlauben. Der service_role-Schlüssel geht durch eine Lücke in der Sperre und erreicht alle sechs.","Row Level Security ist das, was den anon-Schlüssel sicher macht. Ein service_role-Schlüssel geht direkt daran vorbei.","\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend\u002Fwhat-each-key-reaches-1600x820.png",[22,80,82],{"id":81},"die-zwei-familien-von-schlüsseln","Die zwei Familien von Schlüsseln",[84,85,86,105],"table",{},[87,88,89],"thead",{},[90,91,92,96,99,102],"tr",{},[93,94,95],"th",{},"Anbieter",[93,97,98],{},"Schlüssel",[93,100,101],{},"Im Browser sicher?",[93,103,104],{},"Was er tut",[106,107,108,134,155,173,190],"tbody",{},[90,109,110,114,124,131],{},[111,112,113],"td",{},"Supabase",[111,115,116,120,121],{},[117,118,119],"code",{},"sb_publishable_…",", in älteren Projekten ",[117,122,123],{},"anon",[111,125,126],{},[127,128,130],"key-verdict",{"type":129},"safe","Gehört hierhin",[111,132,133],{},"Sagt, um welches Projekt es geht. Jede Anfrage wird weiterhin von deinen Row-Level-Security-Regeln gefiltert.",[90,135,136,138,146,152],{},[111,137,113],{},[111,139,140,120,143],{},[117,141,142],{},"sb_secret_…",[117,144,145],{},"service_role",[111,147,148],{},[127,149,151],{"type":150},"danger","Niemals",[111,153,154],{},"Umgeht Row Level Security vollständig. Liest und schreibt jede Zeile in jeder Tabelle, egal was deine Regeln sagen.",[90,156,157,160,166,170],{},[111,158,159],{},"Stripe",[111,161,162,165],{},[117,163,164],{},"pk_live_…"," (öffentlich)",[111,167,168],{},[127,169,130],{"type":129},[111,171,172],{},"Erstellt Bezahlformulare. Kann kein Geld bewegen und keine Kundendaten lesen.",[90,174,175,177,183,187],{},[111,176,159],{},[111,178,179,182],{},[117,180,181],{},"sk_live_…"," (geheim)",[111,184,185],{},[127,186,151],{"type":150},[111,188,189],{},"Vollzugriff auf das Konto: Abbuchungen, Erstattungen, Auszahlungen, Kundendaten.",[90,191,192,195,198,202],{},[111,193,194],{},"OpenAI \u002F Anthropic",[111,196,197],{},"jeder API-Schlüssel",[111,199,200],{},[127,201,151],{"type":150},[111,203,204],{},"Es gibt keine öffentliche Variante. Jeder Schlüssel belastet direkt dein Konto.",[10,206,207],{},"Das Muster gilt über diese drei hinaus. Bietet ein Anbieter nur eine Sorte\nSchlüssel an, geh davon aus, dass er geheim ist und auf einen Server gehört.",[209,210,212],"callout",{"type":211},"warn",[10,213,214,217,218,220,221,223,224,226],{},[17,215,216],{},"Der Schlüssel, der die meisten erwischt, ist der geheime Supabase-Schlüssel.","\nIn einem älteren Projekt heißt er ",[117,219,145],{}," und sieht dem anon-Schlüssel\nfast identisch aus: gleiches Format, gleiche Länge, gleiche Stelle im Dashboard,\ndirekt nebeneinander. Den falschen zu kopieren ist ein einziger verrutschter\nKlick, und danach geht nichts kaputt: Deine App funktioniert genau wie vorher.\nDas macht ihn so leicht übersehbar. In neueren Projekten ist genau das besser\ngeworden: ",[117,222,142],{}," und ",[117,225,119],{}," sagen schon in den ersten Zeichen,\nwelcher welcher ist.",[22,228,230],{"id":229},"so-erkennst-du-den-unterschied-in-60-sekunden","So erkennst du den Unterschied in 60 Sekunden",[10,232,233,236,237,240,241,244,245,248,249,252],{},[17,234,235],{},"Bei Stripe und den meisten Anbietern reicht das Präfix."," ",[117,238,239],{},"pk_"," ist öffentlich\nund sicher. ",[117,242,243],{},"sk_"," ist geheim und nicht. Manche Anbieter schreiben ",[117,246,247],{},"_test_"," oder\n",[117,250,251],{},"_live_"," in die Mitte. Ein durchgesickerter Testschlüssel ist ein deutlich\nkleineres Problem als ein Live-Schlüssel, aber tausche beide aus.",[10,254,255,258],{},[17,256,257],{},"Bei Supabase hängt es davon ab, wie alt dein Projekt ist."," Supabase hat zwei\nverschiedene Sorten Schlüssel ausgegeben, und beide sind heute in laufenden Apps\nunterwegs.",[10,260,261,236,264,266,267,269,270,274],{},[17,262,263],{},"Neuere Projekte: Präfix lesen, genau wie bei Stripe.",[117,265,119],{}," ist\nder, der in deine App gehört. ",[117,268,142],{}," ist der, den du heute austauschst. Da\nist nichts zu dekodieren. Wofür der Schlüssel da ist, steht vorne drauf.\n",[68,271,273],{"href":272},"\u002Fblog\u002Fsupabase-new-api-keys","Was sich geändert hat und was das für deine App bedeutet",",\nfalls du diese Schlüssel noch nicht kennst.",[10,276,277,280,281,223,283,285],{},[17,278,279],{},"Ältere Projekte: Du musst in den Schlüssel hineinsehen."," Das ursprüngliche\nPaar, ",[117,282,123],{},[117,284,145],{},", sind JWTs: drei durch Punkte getrennte Blöcke\nKauderwelsch, und der mittlere Block ist lesbare Information, keine\nVerschlüsselung. Dort steht die Rolle im Klartext.",[10,287,288],{},"Ein Werkzeug braucht es in keinem Fall. Öffne im Supabase-Dashboard\nSettings → API Keys, dort steht, welcher Schlüssel welcher ist. Willst du lieber\nden Schlüssel prüfen, den du tatsächlich in deiner App gefunden hast: Der\nmittlere Abschnitt eines älteren Schlüssels dekodiert zu etwas wie diesem hier.",[290,291,296],"pre",{"className":292,"code":294,"language":295},[293],"language-text","{\n  \"iss\": \"supabase\",\n  \"ref\": \"abcdefghij…\",\n  \"role\": \"anon\",          ← darauf kommt es an\n  \"iat\": 1750000000\n}\n","text",[117,297,294],{"__ignoreMap":298},"",[74,300],{"alt":301,"caption":302,"src":303},"Ein älterer Supabase-Schlüssel als drei durch Punkte getrennte Abschnitte. Der mittlere ist hervorgehoben und dekodiert entweder zu role anon, als sicher abgehakt, oder zu role service_role, als gefährlich durchgestrichen.","Bei einem älteren Schlüssel ist der mittlere Abschnitt lesbarer Text, keine Verschlüsselung. Ein Wort darin entscheidet, ob der Schlüssel ausgeliefert werden durfte.","\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend\u002Fread-the-role-1600x640.png",[10,305,306,309,310,313],{},[117,307,308],{},"\"role\": \"anon\""," ist der sichere. ",[117,311,312],{},"\"role\": \"service_role\""," ist der, den du heute\naustauschst. Bei einem älteren Schlüssel ist dieses eine Wort der ganze\nUnterschied, und der Grund, warum ein Scanner, der bloß schlüsselförmige\nZeichenketten sucht, Rauschen statt einer Antwort liefert: Er kann dir nicht\nsagen, welchen von zwei identisch aussehenden Schlüsseln du ausgeliefert hast.",[10,315,316,317,72],{},"Wenn du deine App nicht Schlüssel für Schlüssel durchgehen willst: Unser\nkostenloser Scan liest deine Live-Seite und sagt dir, welche davon von außen zu\nsehen sind. Das dauert etwa 20 Sekunden und braucht kein Konto:\n",[68,318,320],{"href":319},"\u002F#scan","App scannen",[22,322,324],{"id":323},"was-passiert-wenn-ein-geheimer-schlüssel-durchsickert","Was passiert, wenn ein geheimer Schlüssel durchsickert",[10,326,327,328,330,331,333],{},"Jede Zeile in deiner Datenbank wird für den lesbar und beschreibbar, der den\nSchlüssel gefunden hat, einschließlich Tabellen, die du deiner App nie\nzugänglich gemacht hast, und einschließlich der persönlichen Daten deiner Nutzer.\nRow Level Security gilt für einen geheimen Supabase-Schlüssel nicht\n(",[117,329,142],{},", oder ",[117,332,145],{}," in einem älteren Projekt). Das ist der Zweck\ndieses Schlüssels.",[10,335,336],{},"Der Schaden ist auch nicht theoretisch. Meist fällt er als Supportnachricht über\nDaten auf, die sich von selbst geändert haben, oder als Tabelle, die plötzlich\nleer ist.",[10,338,339,340,343],{},"Ein durchgesickerter ",[117,341,342],{},"sk_live_","-Schlüssel von Stripe bedeutet Erstattungen,\nAbbuchungen und Kundendaten. Ein durchgesickerter Schlüssel eines\nKI-Anbieters bedeutet eine Rechnung, manchmal eine sehr große, die eintrifft,\nbevor es jemandem auffällt.",[10,345,346],{},"Nichts davon verlangt einen versierten Angreifer. Automatische Scanner\ndurchsuchen öffentliche Seiten genau nach solchen Zeichenketten, und sie müssen\nnicht wissen, wer du bist, um deine zu finden.",[10,348,349,350,72],{},"Wenn du die plattformspezifische Fassung möchtest, was zu prüfen ist: Wir haben\neine verständliche Anleitung für ",[68,351,353],{"href":352},"\u002Fis-your-supabase-app-safe","Supabase-Apps",[22,355,357],{"id":356},"was-jetzt-zu-tun-ist","Was jetzt zu tun ist",[359,360,361],"key-takeaways",{},[362,363,364,372,379,382,391],"ul",{},[365,366,367,368,371],"li",{},"Finde jeden Schlüssel in deiner App und bestimme, welcher es ist. Bei Stripe und bei neueren Supabase-Schlüsseln das Präfix; bei älteren Supabase-Schlüsseln das Feld ",[117,369,370],{},"role"," im Inneren.",[365,373,374,375,378],{},"Findest du einen geheimen Schlüssel im Frontend, ",[17,376,377],{},"tausche ihn zuerst aus",". Ihn aus dem Code zu löschen schließt die Tür nicht: Der alte Wert steckt weiterhin in deiner Versionsgeschichte und in zwischengespeicherten Kopien deiner Seite.",[365,380,381],{},"Verschiebe das, wofür dieser Schlüssel nötig war, auf einen Server: eine Edge Function, eine Serverless-Route, irgendetwas, das nicht der Browser ist.",[365,383,384,385,387,388,390],{},"Schalte Row Level Security für jede Tabelle ein und prüfe dann, dass sie wirklich greift. Ein öffentlicher Schlüssel (",[117,386,119],{}," oder ",[117,389,123],{},") ist nur wegen dieser Regeln sicher; ohne sie liest er deine ganze Datenbank.",[365,392,393],{},"Sieh nach jeder Offenlegung eines geheimen Schlüssels in Abrechnung und Protokolle. Der Austausch stoppt, was danach kommt, nicht das, was schon passiert ist.",[10,395,396,397,401],{},"Wenn du das lieber als Liste durchgehst: Die\n",[68,398,400],{"href":399},"\u002Fchecklist","Sicherheits-Checkliste in 10 Minuten"," deckt diesen Punkt ab und die\nanderen Dinge, die man in einer frisch veröffentlichten App abschalten sollte.",[10,403,404,405,409],{},"Und falls ein Leck je eine Tabelle leert, hängt es ganz davon ab,\n",[68,406,408],{"href":407},"\u002Fblog\u002Fthree-ways-to-back-up-a-supabase-database","was du gesichert hattest",", ob du sie zurückbekommst.",{"title":298,"searchDepth":411,"depth":411,"links":412},3,[413,415,416,417,418,419],{"id":24,"depth":414,"text":25},2,{"id":53,"depth":414,"text":54},{"id":81,"depth":414,"text":82},{"id":229,"depth":414,"text":230},{"id":323,"depth":414,"text":324},{"id":356,"depth":414,"text":357},"Sicherheitsgrundlagen",null,"Dein Supabase-anon-Schlüssel darf öffentlich sein. Der service_role-Schlüssel nicht. Er ignoriert jede Regel, die du setzt. So erkennst du den Unterschied.",false,"md",[426,429,432,435,438],{"q":427,"a":428},"Jemand sagt, mein API-Schlüssel sei offengelegt. Sollte ich in Panik geraten?","Nicht bevor du weißt, um welchen Schlüssel es geht. Beginnt er mit pk_ oder ist es ein Supabase-anon-Schlüssel, ist er für die Öffentlichkeit gedacht und alles ist in Ordnung. Beginnt er mit sk_ oder ist es ein service_role-Schlüssel, tausche ihn sofort aus und sieh dann nach, worauf er Zugriff hatte.",{"q":430,"a":431},"Kann ich den Schlüssel nicht einfach verstecken?","Nein. Alles, was dein Browser benutzen kann, kann ein Besucher auch lesen. Minifizieren, Umbenennen oder Verschleiern hält jemanden nur ein paar Sekunden auf. Die Lösung ist nie, einen geheimen Schlüssel im Frontend zu verstecken, sondern ihn auf einen Server zu verschieben oder einen öffentlichen Schlüssel zu verwenden, der von vornherein sichtbar sein durfte.",{"q":433,"a":434},"Warum gibt mir Supabase einen Schlüssel, den jeder lesen kann?","Weil der anon-Schlüssel nicht das ist, was deine Daten schützt. Er sagt nur, mit welchem Projekt du sprichst. Der eigentliche Schutz ist Row Level Security, die Zeile für Zeile entscheidet, was jeder Besucher sehen darf. Deshalb ist ein anon-Schlüssel mit eingeschalteter RLS unproblematisch, und derselbe Schlüssel ohne RLS eine offene Datenbank.",{"q":436,"a":437},"Mein Supabase-Schlüssel beginnt mit sb_publishable_. Ist das derselbe wie der anon-Schlüssel?","Er hat dieselbe Aufgabe. Supabase hat seinen Schlüsseln neue Namen gegeben: sb_publishable_ hat den anon-Schlüssel abgelöst, sb_secret_ den service_role-Schlüssel. Ein Schlüssel, der mit sb_publishable_ beginnt, gehört also in deine App. Einer, der mit sb_secret_ beginnt, niemals. Ältere Projekte tragen weiterhin die ursprünglichen anon- und service_role-Schlüssel, und die funktionieren weiter; unter Umständen siehst du beide Paare nebeneinander im Dashboard.",{"q":439,"a":440},"Ich habe bereits einen geheimen Schlüssel in meine App eingefügt. Was jetzt?","Tausche ihn zuerst aus: Erzeuge im Dashboard des Anbieters einen neuen Schlüssel und widerrufe den alten. Nur das schließt die Tür wirklich. Ihn aus dem Code zu löschen reicht nicht, weil die alte Version noch in deiner Versionsgeschichte und in zwischengespeicherten Kopien steckt. Verschiebe danach die Arbeit, die ihn brauchte, auf einen Server, und prüfe Abrechnung und Protokolle auf Dinge, die nicht von dir stammen.","\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend\u002Fcard-800x500.png",[443,444,445,446,447,448,449,450],"supabase anon key","service_role key","sb_publishable key","sb_secret key","supabase neue api-schlüssel","stripe publishable key","api-schlüssel im frontend","api-schlüssel sichtbar",{},true,"Welche API-Schlüssel sind im Frontend sicher?","\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend","2026-08-09",{"title":5,"description":422},"blog\u002Fwhich-api-keys-are-safe-in-your-frontend",[459,460,461],"Einen API-Schlüssel im Code deiner App zu finden ist nicht automatisch ein Problem. Manche Schlüssel gehören genau dorthin.","Öffentliche Schlüssel sind im Browser sicher. Geheime nicht. Einer davon im Frontend ist eine offene Kasse.","Zwei Prüfungen trennen sie in unter einer Minute: Präfix lesen, und bei einem älteren Supabase-Schlüssel die Rolle dekodieren.","2026-08-12","onQwT1D4d1fRntjaS0LNNNH1g0hMVJLyEGFXlmcGAKA",1787826048205]