Zum Inhalt springen

Sicherheitsgrundlagen

Ein offengelegter AWS-Schlüssel im Frontend ist kein OpenAI-Key

Ein im Frontend offengelegter AWS-Zugriffsschlüssel liest und schreibt deinen Speicher. Die Lösung ist meist eine presigned URL, kein neuer Schlüssel.

Vlad Tkachenko9 Min. Lesezeit
Eine Seite App-Code mit einem kurzen hellen Wert und einem langen verdeckten darunter, ein Schlüssel über ihrer Ecke, dahinter ein Regal voller Dateien.

Kurz gesagt

  • Ein im Frontend offengelegter AWS-Zugriffsschlüssel ist ein anderes Problem als ein Schlüssel, der nur Geld ausgeben kann. Was er erreicht, entscheiden seine Berechtigungen.
  • Zwei Zeichenketten signieren eine AWS-Anfrage: eine Kennung, die mit `AKIA` beginnt, und eine geheime Hälfte. Eine ohne die andere signiert nichts.
  • Ein neuer Schlüssel an derselben Stelle ist derselbe Fund mit einem anderen Wert. Die Lösung ist eine presigned URL, damit der Browser überhaupt keine Zugangsdaten hält.
  • Wir haben einen in 9 von 31.056 gescannten Apps gefunden, bei denen diese Prüfung durchlief.

Jemand öffnet deine App im Browser, drückt F12 und findet eine Zeichenkette, die mit AKIA beginnt, mitten in deinem Frontend-Code. Oder GitHub schreibt dir, dass ein Commit vom vergangenen März AWS-Zugangsdaten enthält. Der Rat, der mit beidem kommt, ist immer derselbe: rotiere den Schlüssel. Bei den meisten Schlüsseln ist das fast die ganze Antwort.

Hier ist der Teil, den eine Anleitung nach der anderen falsch macht. Ein im Frontend offengelegter AWS-Zugriffsschlüssel ist kein Schlüssel, der Geld ausgibt. Er ist ein Schlüssel, der Dinge öffnet, und die beiden gehen in unterschiedliche Richtungen schief. Ein Schlüssel, der nur ausgibt, ist eine Firmenkarte: jemand macht eine Rechnung, du sperrst die Karte, und der Schaden ist eine Zahl, die du auf einem Auszug lesen kannst. Ein Schlüssel, der Dinge öffnet, ist der Schlüsselbund zum Lager. Was er erreicht, hängt davon ab, was beim Anfertigen daraufgeschrieben wurde, und das kannst du auf einem einzigen Bildschirm in deiner AWS-Konsole nachlesen.

Was bedeutet AKIA am Anfang eines Schlüssels?

Es kennzeichnet einen langlebigen Zugriffsschlüssel, der entweder einem Benutzer in deinem Konto oder dem Root-Login des Kontos gehört. AWS schreibt das Präfix in seiner eigenen Kennungsreferenz auf: AKIA für Zugriffsschlüssel und ASIA für die temporären, die der Token-Dienst ausgibt. Die ersten vier Zeichen sagen dir also, welche Sorte du vor dir hast, und AKIA ist die Sorte ohne Ablaufdatum. Er funktioniert, bis ihn jemand abschaltet.

AWS-Zugangsdaten sind zwei Zeichenketten, und eine Anfrage braucht beide, um signiert zu werden. Die erste ist die Zugriffsschlüssel-Kennung, also der Teil, der mit AKIA beginnt. Die zweite ist der geheime Zugriffsschlüssel, eine längere Zeichenkette ganz ohne Präfix davor. Die Kennung allein signiert nichts.

Das lohnt sich zu prüfen, bevor du entscheidest, wie schlimm dieser Morgen ist, denn es ändert die Antwort. Wenn dein Bundle die AKIA-Zeichenkette trägt und nichts, was nach ihrer geheimen Hälfte aussieht, hat ein Besucher beim Lesen deiner Seite den Namen des Schlüssels bekommen und nicht den Schlüssel. In der Praxis reisen die beiden meist zusammen, denn was eines in den Browser gebracht hat, hat beide gebracht: ein Paar Umgebungsvariablen namens AWS_ACCESS_KEY_ID und AWS_SECRET_ACCESS_KEY, gelesen von Code, der auf einem Server hätte laufen sollen.

Beide Hälften zusammen signieren eine Anfrage. Die Kennung allein ist ein Name, und ein Name öffnet nichts.

Was kann jemand mit meinem AWS-Zugriffsschlüssel anfangen?

Was immer seine Berechtigungen erlauben, und nichts darüber hinaus. Es gibt also drei Antworten.

Was kann er lesen? Jeden S3-Bucket, den die Richtlinie aufführt, und jedes Objekt darin, auch die, auf die du nie von irgendwo verlinkt hast. Ein Bucket, den nichts in deiner App erwähnt, ist vor Zugangsdaten, die ihn auflisten dürfen, nicht verborgen.

Was kann er schreiben? Dieselben Orte, und das ist die Hälfte, die man vergisst. Ein Schlüssel, der schreiben kann, kann auch überschreiben und löschen, und eine an Ort und Stelle ersetzte Datei sieht genau aus wie die, die du hochgeladen hast, bis sie jemand öffnet.

Was kann er starten? Das ist die mit dem Zähler. Eine Richtlinie, die weit genug für Rechenleistung ist, startet Rechenleistung, und die rechnet stündlich ab, solange sie läuft. Nichts an der Browser-Kopie des Schlüssels begrenzt, wie viel von deinem Konto sie erreicht; die Richtlinie ist die einzige Grenze.

Die schlimmste Fassung davon ist ein Schlüssel, der für das Root-Login des Kontos angefertigt wurde. AWS schreibt in seinen eigenen Hinweisen zum Root-Benutzer, dass dieser uneingeschränkten Zugriff auf alle AWS-Dienste, Ressourcen und Abrechnungsdaten hat, und rät davon ab, überhaupt Zugriffsschlüssel dafür anzulegen. Wenn der Schlüssel auf deiner Seite mit AKIA beginnt und dem Root-Benutzer gehört, ist das Offengelegte das ganze Konto und nicht ein Bucket.

Rate also bei nichts davon. Öffne IAM, finde den Benutzer, dem der Schlüssel gehört, und lies die Richtlinien an ihm. Das ist ein Bildschirm, und er beantwortet alle drei Fragen oben.

Reicht es, ihn einfach zu rotieren?

Deaktiviere den offengelegten Schlüssel heute, und setze keinen Ersatz an dieselbe Stelle.

Deaktivieren ist der richtige erste Schritt und sanfter, als es klingt. AWS lässt einen Benutzer bis zu zwei aktive Zugriffsschlüssel gleichzeitig halten, und das gibt es genau dafür, dass ein Ersatz hochkommen kann, bevor der alte heruntergeht. Deaktivieren lässt den Schlüssel liegen und abgeschaltet, und er lässt sich wieder einschalten; Löschen ist unumkehrbar, und die geheime Hälfte eines gelöschten Schlüssels ist nicht wiederherstellbar. Also deaktivieren, schauen, was kaputtgeht, und danach löschen.

Was das nicht abschließt, ist einen neuen Schlüssel anzulegen und ihn dorthin zu setzen, wo der alte war. Beim Leck ging es nie wirklich um diesen einen Wert. Es ging darum, dass ein Browser Zugangsdaten ohne Ablaufdatum hält, und alles, was deine Seite herunterlädt, lädt jeder Besucher herunter. Eine frische AKIA-Zeichenkette im selben Bundle kommt beim nächsten Scan als derselbe Fund zurück.

AWS sagt das klar in seinem Security Audit Guide, dort über mobile Anwendungen: sie sollten niemals eingebettete Zugriffsschlüssel enthalten, auch nicht verschlüsselt. Ein Browser-Bundle liest sich leichter als eine App-Binärdatei, also gilt dieselbe Antwort hier und kostet einen Fremden weniger Arbeit.

Wenn du den Schlüssel bereits an einer öffentlichen Stelle gefunden hast, kommt es auf die Reihenfolge an, und was zu tun ist, wenn ein API-Key geleakt wurde legt diese Reihenfolge für Schlüssel jeder Art hin.

Was eine presigned URL stattdessen tut

Sie lässt den Browser genau eine Sache mit genau einer Datei tun, ohne überhaupt Zugangsdaten zu halten.

Dein eigener Server behält den Zugriffsschlüssel, wo ein Besucher ihn nicht lesen kann. Wenn deine Seite eine Datei in S3 legen oder eine herausholen muss, fragt sie deinen Server, und dein Server signiert eine URL für genau dieses Objekt und genau diese Aktion und reicht sie zurück. Der Browser benutzt die URL und bekommt nichts weiter dazu. AWS beschreibt eine presigned URL als temporären Zugriff auf S3-Objekte ohne AWS-Zugangsdaten, und derselbe Mechanismus deckt Downloads wie Uploads ab.

Zurück zum Lager. Eine presigned URL heißt, den Kurier an der Tür mit genau der Kiste zu treffen, wegen der er gekommen ist, statt ihm den Schlüsselbund zu geben und darauf zu vertrauen, dass er sie findet. Was der Kurier mitnimmt, hört auf zu funktionieren, wenn seine Uhr abgelaufen ist.

Für den Fall, dass jede angemeldete Person an ihre eigenen Dateien kommt, verweist AWS wieder woandershin: seine Hinweise zum Sichern von Zugriffsschlüsseln sagen, mobile Anwendungen sollten Amazon Cognito für Identitäten nutzen, statt Zugriffsschlüssel einzubetten. Was Cognito dem Browser gibt, sind temporäre Zugangsdaten, die ASIA-Sorte vom Anfang dieses Artikels, die nach einer Weile von selbst aufhört zu funktionieren. Eine Kopie davon, die am Dienstag von deiner Seite abgegriffen wird, ist am Mittwoch schon tot, und genau diese Eigenschaft hat ein AKIA-Schlüssel nicht.

Der obere Weg legt etwas in den Browser, das auf jede Datei wirkt, morgen genauso wie heute. Der untere gibt ihm eine Datei und eine Frist.

Wie prüfe ich, ob meine App einen AWS-Schlüssel ausliefert?

Durchsuche das, was der Browser heruntergeladen hat, nicht das, was in deinem Projekt liegt. Das sind zwei verschiedene Dateien, und es zählt die, die deine Besucher bekommen.

Im Browser. Öffne deine veröffentlichte Seite, drücke F12 und suche im geladenen JavaScript nach AKIA. Chrome und Edge durchsuchen aus dem Sources-Panel alle geladenen Dateien auf einmal.

In deinem Projekt. Suche nach AKIA, AWS_ACCESS_KEY_ID und AWS_SECRET_ACCESS_KEY. Suche dann nach den zwei Präfixen, die einen Wert absichtlich ins Bundle legen, VITE_ und NEXT_PUBLIC_, und lies jeden Wert dahinter. Warum diese zwei Präfixe alles veröffentlichen, was sie benennen, ist die Mechanik hinter den meisten davon, und es ist eine Regel des Builds, die niemand versehentlich getippt hat.

Von außen. Unser kostenloser Scan liest deine veröffentlichte Seite so, wie ein Fremder es täte, und meldet, welche Zugangsdaten er in dem sieht, was du ausgeliefert hast, diese hier eingeschlossen. Er dauert etwa 20 Sekunden und braucht kein Konto: App kostenlos scannen.

Über alle Apps hinweg, die wir gescannt haben, ist das ein seltener Fund: ein AWS-Zugriffsschlüssel tauchte in 9 von 31.056 Apps auf, bei denen diese Prüfung durchlief. Weit häufiger kommen Google-Schlüssel, die meist in Ordnung sind, und OpenAI-Schlüssel, die es meist nicht sind. Was aus so gebauten Apps tatsächlich herausfließt stellt sie alle mit den Zahlen nebeneinander.

Was der Schlüssel getan hat, während er draußen war

Öffne die CloudTrail-Ereignisliste und filtere sie nach der Zugriffsschlüssel-Kennung.

Die Ereignisliste ist in jedem AWS-Konto an, ohne dass etwas eingeschaltet werden muss, sie hält die letzten 90 Tage, und sie kostet nichts extra. Jeder Eintrag trägt die Kennung des Schlüssels, der den Aufruf gemacht hat, du kannst also nachlesen, was dein Schlüssel getan hat. Das beantwortet die Fragen zur Konfiguration: ein angelegter Bucket, eine geänderte Richtlinie, ein hinzugefügter Benutzer.

Dann gibt es den Teil, den man vorher wissen sollte. Die Ereignisliste hält Management-Ereignisse. Ein Objekt aus S3 zu lesen ist ein Daten-Ereignis, und AWS sagt ausdrücklich, dass Trails diese nicht standardmäßig protokollieren und dass Datenereignisse gar nicht in der Ereignisliste erscheinen. Sie einzuschalten zeichnet ab diesem Moment auf.

Die ehrliche Lesart ist also diese. Wenn der Schlüssel benutzt wurde, um dein Konto zu verändern, zeigt es dir das Protokoll. Wenn er benutzt wurde, um den Inhalt eines Buckets herunterzuladen, zeigt es das wahrscheinlich nicht, und du entscheidest, was du deinen Kunden sagst, auf der Grundlage, dass es passiert sein kann.

Wie ein Schlüssel aus dem nächsten Build bleibt

Zugangsdaten gehen zur Build-Zeit in den Browser, also ist der nächste Deploy der, auf den es zu achten gilt. Der Schlüssel, den du heute herausnimmst, ist an dem Nachmittag wieder drin, an dem jemand eine Funktion mit S3 ergänzt und einen Agenten bittet, sie zu verdrahten.

Reeve Monitor liest deine veröffentlichte Seite für dich erneut:

  • alle neun Prüfungen jede Stunde, für bis zu drei Apps
  • eine Nachricht, wenn sich ein Ergebnis ändert, damit ein Schlüssel, der am Dienstag auftaucht, nicht wartet, bis du das nächste Mal nachsiehst
  • ob die App erreichbar ist, alle 60 Sekunden
  • ein monatlicher Bericht über das Gesehene

Wenn deine App ihre Daten in einem Supabase-Projekt hält, bewahrt Reeve Care davon ebenfalls eine Kopie:

  • eine verschlüsselte Kopie deiner Supabase-Datenbank jede Nacht, dort abgelegt, wo dein Projekt sie nicht erreicht
  • jede Kopie geprüft, bevor sie zählt, durch Zählen der Zeilen in jeder Tabelle
  • eine Wiederherstellung mit einem Klick, wenn du sie brauchst
  • auch deine hochgeladenen Dateien, sobald du Storage-Zugangsdaten verbindest
  • alles, was Monitor tut

Jede dieser neun Prüfungen beschreibt, was ein Fremder erreichen kann. Eine Kopie der Datenbank von gestern Nacht beantwortet die andere Frage, nämlich was jemand bereits verändert hat, während der Schlüssel draußen war.

Was diese Woche zu tun ist

Was zu tun ist

  • Öffne deine veröffentlichte Seite, drücke F12 und suche im geladenen JavaScript nach AKIA. Das ist die Datei, die deine Besucher haben, und nur die zählt.
  • Wenn du einen findest, deaktiviere ihn heute in IAM. Deaktivieren ist umkehrbar und wirkt sofort; Löschen ist es nicht, und die geheime Hälfte lässt sich nicht wiederherstellen.
  • Lies die Richtlinien am Benutzer des Schlüssels, bevor du entscheidest, wie ernst das ist. Was er lesen, was er schreiben und was er starten kann, sind drei getrennte Antworten.
  • Ersetze das Muster statt des Werts. Dein Server hält den Schlüssel und signiert eine presigned URL für ein Objekt, oder Amazon Cognito gibt dem Browser temporäre Zugangsdaten, die von selbst ablaufen.
  • Filtere die CloudTrail-Ereignisliste für die letzten 90 Tage nach dem Schlüssel. Sie zeigt dir, was der Schlüssel konfiguriert hat, und sie zeigt dir nicht, welche Dateien er gelesen hat, sofern Datenereignisse nicht schon eingeschaltet waren.

Fang mit der F12-Suche an, denn sie klärt in einer Minute, ob du überhaupt ein Problem hast. Wenn sie etwas zutage fördert, deckt die Sicherheits-Checkliste in 10 Minuten den Rest dessen ab, was eine frisch gestartete App gern offen lässt, und ein Geheimnis in eine Edge Function verschieben ist das Muster für jeden Schlüssel, der nie auf der Seite hätte sein sollen.

FAQ

Sind AWS-Schlüssel im Frontend-Code jemals in Ordnung?

Nein. AWS sagt das in seinem eigenen Security Audit Guide über mobile Apps: Anwendungen sollten niemals eingebettete Zugriffsschlüssel enthalten, auch nicht verschlüsselt. Ein Browser-Bundle liest sich leichter als eine App-Binärdatei, also gilt dieselbe Antwort hier und kostet einen Fremden weniger Arbeit. Wenn deine Seite wirklich S3 erreichen muss, sind die vorgesehenen Wege eine presigned URL, die dein eigener Server signiert, oder temporäre Zugangsdaten von Amazon Cognito, die von selbst ablaufen.

Was kann jemand mit meinem AWS-Zugriffsschlüssel anfangen?

Genau das, was die Berechtigungen dahinter erlauben, weshalb es keine einzelne Antwort gibt. Ein Schlüssel an einem Benutzer mit Lesezugriff auf einen Bucket liest diesen Bucket. Ein Schlüssel an einem Administrator tut alles, was ein Administrator tut, einschließlich Maschinen zu starten, die stündlich abrechnen. Ein Schlüssel des Root-Benutzers des Kontos ist der schlimmste Fall, denn AWS schreibt, dass der Root-Benutzer uneingeschränkten Zugriff auf alle Dienste, Ressourcen und Abrechnungsdaten hat. Öffne IAM und lies die Richtlinien am Schlüssel, bevor du entscheidest, wie besorgt du sein musst.

Was ist eine presigned URL?

Eine lange URL, mit der ein Browser genau eine Sache mit genau einer Datei in S3 tun darf, für eine festgelegte Anzahl Sekunden, ohne irgendwelche AWS-Zugangsdaten zu halten. Dein eigener Server hält den Schlüssel und signiert die URL auf Anfrage. AWS beschreibt presigned URLs als temporären Zugriff auf S3-Objekte ohne AWS-Zugangsdaten, und sie funktionieren für Downloads wie für Uploads.

Wie prüfe ich, ob meine App einen AWS-Schlüssel ausliefert?

Durchsuche das, was dein Browser heruntergeladen hat, und nicht das, was in deinem Projekt liegt. Öffne deine veröffentlichte Seite, drücke F12 und suche im geladenen JavaScript nach AKIA. Durchsuche dann dein Projekt nach AKIA, AWS_ACCESS_KEY_ID und AWS_SECRET_ACCESS_KEY und nach jedem Variablennamen, der mit VITE_ oder NEXT_PUBLIC_ beginnt und so etwas hält, denn diese Präfixe sind es, die einen Wert überhaupt erst ins Bundle legen.

Mein AWS-Schlüssel liegt auf GitHub. Was jetzt?

Deaktiviere ihn zuerst in IAM, das ist umkehrbar und wirkt sofort, und lege dann einen Ersatz für den Server an, der ihn gebraucht hat. Ihn aus dem Code zu löschen schließt nichts, denn der alte Wert bleibt in deiner Commit-Historie und in jedem Klon, den jemand gezogen hat. Öffne danach die CloudTrail-Ereignisliste und filtere nach dem Schlüssel, um zu sehen, was er getan hat.

Geschrieben von

Vlad Tkachenko

Gründer, Reeve

Ich schaue mir den ganzen Tag Apps an, die mit Lovable, Bolt, v0, Cursor und Replit gebaut wurden, und die kurze Liste von Fehlern, die darin immer wieder auftauchen.

Mehr über den Autor

Weiterlesen

Alle Artikel

Unsicher, wie es um deine eigene App steht?

Starte einen kostenlosen Scan und erhalte in rund 20 Sekunden eine verständliche Note von A bis F. Ohne Konto, ohne Karte.

App kostenlos scannen

Automatisierte externe Prüfung, kein vollständiges Audit. Das Fehlen von Funden ist keine Garantie für Sicherheit.