Wie einfach ist es, JavaScript (in einem Browser) zu hacken?

37

Meine Frage hat mit JavaScript-Sicherheit zu tun.

Stellen Sie sich ein Authentifizierungssystem vor, bei dem Sie ein JavaScript-Framework wie Backbone oder AngularJS verwenden und sichere Endpunkte benötigen. Das ist kein Problem, da der Server immer das letzte Wort hat und überprüft, ob Sie berechtigt sind, das zu tun, was Sie wollen.

Aber was ist, wenn Sie ein wenig Sicherheit benötigen, ohne den Server einzubeziehen? Ist das möglich?

Angenommen, Sie haben ein clientseitiges Routingsystem und möchten, dass eine konkrete Route für angemeldete Benutzer geschützt wird. Sie rufen den Server an und fragen, ob Sie geschützte Routen besuchen dürfen, und fahren fort. Das Problem ist, dass Sie beim Pingen des Servers die Antwort in einer Variablen speichern. Wenn Sie also das nächste Mal zu einer privaten Route gehen, wird überprüft, ob Sie bereits angemeldet sind (kein Ping an den Server) Auf die Antwort wird es gehen oder nicht.

Wie einfach ist es für einen Benutzer, diese Variable zu ändern und Zugriff zu erhalten?

Meine Sicherheits- (und JavaScript-) Kenntnisse sind nicht besonders gut. Aber wenn sich eine Variable nicht im globalen Bereich befindet und sich im privaten Teil eines Modulmusters befindet, das nur Getter, aber keine Setter enthält, können Sie das Ding dann heraushacken?

Jesus Rodriguez
quelle
29
All diese langen Antworten. Kurz gesagt, um Ihnen Header zu beantworten, "sehr hackbar". Um Ihre ersten 2 Fragen miteinander zu beantworten, "ohne Server haben Sie die Sicherheit verloren" && "Nein". Zur Beantwortung der dritten Frage "Sehr einfach" und schließlich "Ja, mit Leichtigkeit". Es geht los. Alle Fragen beantwortet. : P
SpYk3HH
Das beste Beispiel ist mein Blogbeitrag über das Hinzufügen von jQuery zu Webseiten. spyk3lc.blogspot.com/2013/05/… Nun, junger Padawan, geh und probiere es aus. Sehen Sie, wie einfach es ist, jQuery zu einer Site hinzuzufügen, auf der es noch nicht vorhanden ist, und verwenden Sie dann die jQuery, um ganz einfach einen Teil des Visiers ohne lange Javascript-Zeilen zu bearbeiten. Boom!
SpYk3HH
7
Einmal war bei der Registrierung eines Domainnamens die Telefonnummer ein Pflichtfeld, dies wurde jedoch nur im Javascript erzwungen - nicht auf der Serverseite. Also habe ich es deaktiviert, indem ich eine Funktion neu definiert habe (mit Firebug), und voilà! Sie haben meine Telefonnummer nicht.
Izkata
8
manipulate any part of the sight without long lines site vs sight
mplungjan
8
Professionelle Web-Programmierer müssen so etwas richtig machen. Bitte. Es ist mehr peinlich als eine Grammatik-Nazi-Sache :) plus.google.com/u/0/+MonaNomura/posts/h9ywDhfEYxT
mplungjan

Antworten:

26

Lesen Sie bitte die Antwort von Joachim, bevor Sie diese lesen . Er deckt die allgemeinen Gründe für die clientseitige Sicherheitslücke ab. Nun zu einem Vorschlag, wie Sie dieses Problem umgehen könnten ...

Ein sicheres Schema für die Client-Server-Kommunikation, ohne sich bei jeder Anforderung manuell beim Server authentifizieren zu müssen:

Sie sind immer noch im Stich gelassen der Server das letzte Wort haben, und der Server noch alles validieren der Kunde sagt, aber es geschieht transparent.

Nehmen Sie das HTTPS- Protokoll an, um Man-in-the-Middle-Angriffe (MITMA) zu verhindern.

  • Der Client gibt zum ersten Mal einen Handshake mit dem Server aus, und der Server generiert einen öffentlichen Schlüssel für den Client und behält einen privaten Schlüssel bei, der ein asymmetrisches Verschlüsselungsschema verwendet. Der Client speichert den "öffentlichen" Schlüssel des Servers im lokalen Speicher, verschlüsselt mit einem sicheren Passwort, das Sie nirgendwo speichern.

  • Der Client ist jetzt offline. Der Client möchte vertrauenswürdige Aktionen ausführen. Der Client gibt sein Passwort ein und greift nach dem öffentlichen Schlüssel des Servers.

  • Der Client führt jetzt Aktionen basierend auf dem Wissen über diese Daten aus, und der Client verschlüsselt jede Aktion, die er ausführt, mit dem öffentlichen Schlüssel des Servers für diesen Client .

  • Wenn der Client online ist, sendet der Client seine Client-ID und alle vom Client ausgeführten Aktionen werden verschlüsselt mit dem öffentlichen Schlüssel des Servers an den Server gesendet.

  • Der Server entschlüsselt die Aktionen und vertraut bei korrektem Format darauf, dass sie vom Client stammen.

Hinweis:

  • Sie können das Clientkennwort nirgendwo speichern, da ein Angreifer sonst den Schlüssel abrufen und die Aktionen als seine eigenen signieren könnte. Die Sicherheit dieses Schemas hängt ausschließlich von der Integrität des Schlüssels ab, den der Server für den Client generiert. Der Client muss weiterhin beim Server authentifiziert werden, wenn er nach diesem Schlüssel fragt.

  • Tatsächlich verlassen Sie sich aus Sicherheitsgründen immer noch auf den Server und nicht auf den Client. Jede Aktion, die der Client ausführt, muss auf dem Server überprüft werden.

  • Es ist möglich, externe Skripte in Web Workern auszuführen . Denken Sie daran, dass jede JSONP- Anfrage, die Sie haben, jetzt ein viel größeres Sicherheitsproblem darstellt. Sie müssen den Schlüssel um jeden Preis schützen. Sobald Sie es verlieren, kann sich ein Angreifer als Benutzer ausgeben.

  • Dies entspricht Ihrer Anforderung, dass kein Ping an den Server ausgeführt wird. Ein Angreifer kann eine HTTP-Anfrage mit gefälschten Daten nicht einfach imitieren, wenn er den Schlüssel nicht kennt.

  • Die Antwort von Joachim ist immer noch richtig . Tatsächlich führen Sie immer noch die gesamte Authentifizierung auf dem Server durch . Das Einzige, was Sie hier gespeichert haben, ist die Notwendigkeit, das Passwort jedes Mal beim Server zu überprüfen. Sie müssen jetzt nur den Server einbeziehen, wenn Sie ein Commit durchführen oder aktualisierte Daten abrufen möchten. Wir haben hier lediglich einen vertrauenswürdigen Schlüssel auf der Clientseite gespeichert und den Client erneut validieren lassen.

  • Dies ist ein recht verbreitetes Schema für Anwendungen mit nur einer Seite (z. B. mit AngularJS).

  • Ich bezeichne den öffentlichen Schlüssel des Servers als "öffentlich", da dies in Schemata wie RSA bedeutet , aber es handelt sich tatsächlich um vertrauliche Informationen im Schema, die geschützt werden sollten.

  • Ich würde das Passwort nirgendwo im Speicher behalten. Ich würde den Benutzer veranlassen, jedes Mal, wenn er mit der Ausführung von Offline-Code beginnt, sein "Offline" -Passwort zu übermitteln.

  • Rollen Sie nicht Ihre eigene Kryptographie - verwenden Sie eine bekannte Bibliothek wie die von Stanford zur Authentifizierung.

  • Nehmen Sie diesen Rat wie er ist . Wenden Sie sich an einen Sicherheitsexperten, bevor Sie diese Art der Authentifizierung in einer unternehmenskritischen Anwendung implementieren . Dies ist ein ernstes Problem, das sowohl schmerzhaft als auch leicht falsch zu verstehen ist.

Es ist wichtig, dass keine anderen Skripte Zugriff auf die Seite haben. Dies bedeutet, dass Sie nur externe Skripte mit Webworkern zulassen. Sie können keinen anderen externen Skripten vertrauen, die Ihr Kennwort abfangen könnten, wenn der Benutzer es eingibt.

Verwenden Sie ein promptund kein Inline-Kennwortfeld, wenn Sie sich nicht sicher sind und die Ausführung nicht verzögern (das heißt, es sollte nicht so lange funktionieren, bis Ereignisse darauf zugreifen können, sondern nur im Synchronisierungscode). Und speichern Sie das Kennwort nicht in einer Variablen. Dies funktioniert wiederum nur, wenn Sie darauf vertrauen, dass der Computer des Benutzers nicht gefährdet ist (obwohl dies auch für die Überprüfung gegen einen Server gilt).

Ich möchte noch einmal hinzufügen, dass wir dem Kunden immer noch nicht vertrauen . Sie können dem Kunden nicht alleine vertrauen, und ich denke, Joachim's Antwort nagelt es. Wir haben nur den Vorteil gewonnen, dass wir den Server nicht pingen müssen, bevor wir mit der Arbeit beginnen.

Zugehöriges Material:

Benjamin Gruenbaum
quelle
3
"Nicht Ihre eigene Krypto rollen" gilt für Protokolle ebenso wie für Primitive, wenn nicht sogar noch mehr, weil die Leute normalerweise nicht dumm genug sind, ihre eigenen Primitive zu erstellen, aber sie denken, sie können ein Protokoll erstellen, das in Ordnung ist . Ich verstehe auch nicht, warum RSA hier notwendig ist. Da Sie HTTPS verwenden, können Sie ein gemeinsames 16-32-Byte-Geheimnis generieren, das bei zukünftigen Anforderungen gesendet werden muss. Wenn Sie dies tun, müssen Sie natürlich die zeitinvariante Gleichheitsprüfung für die Zeichenfolge verwenden ...
Reid,
2
+1 @Reid Ja, ich habe gerade eine Diskussion darüber mit einem Experten darüber geführt. Ich habe das primitive Schema hier grob auf ein Protokoll gestützt, das ich kennengelernt habe (von Rabin IIRC), aber zumindest, bis ich die Einzelheiten herausgefunden habe (und zum Beispiel begründe, warum in diesem Fall eine asymmetrische Verschlüsselung erforderlich ist). Verwenden Sie das in dieser Antwort vorgeschlagene Schema nicht, ohne zuvor einen Sicherheitsexperten zu konsultieren . Ich habe diesen Ansatz an mehreren Stellen gesehen, aber in der Praxis bedeutet das, wenn überhaupt, sehr wenig. Ich habe auch die Antwort bearbeitet, um das zu verbessern.
Benjamin Gruenbaum
Das Verwenden einer Eingabeaufforderung bietet nur wenig Sicherheit. Ein Angreifer kann die window.promptMethode überschreiben , um die Passphrase abzufangen, oder eine eigene Eingabeaufforderung starten (möglicherweise innerhalb eines Iframes!). Ein Passwortfeld hat einen zusätzlichen Vorteil: Die Zeichen werden nicht angezeigt.
Rob W
@ RobW Natürlich ist dieses ganze Schema wertlos, wenn die Seite kompromittiert wurde. Wenn der Angreifer Zugriff hat, um JavaScript auf der Seite auszuführen, sind wir fertig. Die Idee hinter prompt war, dass es blockiert, aber Sie haben Recht, jeder Sicherheitsvorteil, den es bietet, ist zweifelhaft. Siehe den letzten Link in der Liste.
Benjamin Gruenbaum
1
Als allererstes. Tolle Antwort, ich glaube, ich kann nichts anderes verlangen. Andererseits wollte ich Haustierprojekte für mich machen (und natürlich für diejenigen, die es benutzen wollen) und vielleicht ist das übertrieben (oder vielleicht auch nicht). Ich meine, ich möchte nichts Ernstes tun und ich fürchte, dass ich diese Art von Auth, die Sie erklärt haben, nicht rollen kann, mangelndes Wissen. Ich glaube, ich würde einen einfachen 401-Scheck rollen, oder wenn ich keine Anfrage habe, pinge ich den Server jedes Mal an, wenn ich auf diese Art von Routen zugreife. Auth-Token ist ebenfalls eine Option (und möglicherweise die engste Verbindung zu dem, was Sie hier AFAIK erklärt haben). Vielen Dank :)
Jesus Rodriguez
89

Es ist ganz einfach: Jeder Sicherheitsmechanismus, bei dem der Client nur das tut, was er tun soll, kann gefährdet werden, wenn ein Angreifer die Kontrolle über den Client hat.

Sie können Sicherheitskontrollen auf dem Client, sondern nur , um effektiv als einen „Cache“ (um zu vermeiden , einen teueren Roundtrip zum Server machen , wenn bereits der Kunde weiß , dass die Antwort sein wird „nein“) zu handeln.

Wenn Sie Informationen von einer Gruppe von Benutzern behalten möchten, stellen Sie sicher, dass der Client dieser Benutzer diese Informationen niemals erhält. Wenn Sie diese "geheimen Daten" zusammen mit den Anweisungen "aber bitte nicht anzeigen" senden, wird es trivial, den Code zu deaktivieren, der diese Anforderung überprüft.

Wie Sie sehen, werden in dieser Antwort keine JavaScript- / Browser-Besonderheiten erwähnt. Das liegt daran, dass dieses Konzept das gleiche ist, egal was Ihr Kunde ist. Es spielt keine Rolle, ob es sich um einen Fat Client (herkömmliche Client / Server-App), eine Webanwendung der alten Schule oder eine App für eine einzelne Seite mit umfangreichem clientseitigem JavaScript handelt.

Sobald Ihre Daten den Server verlassen, müssen Sie davon ausgehen, dass ein Angreifer vollen Zugriff darauf hat.

Joachim Sauer
quelle
Vielen Dank. Wäre schön, wenn Sie es ein wenig näher erläutern könnten, mein Sicherheitswissen ist nicht so gut und der einzige Teil, den ich verstehe, ist, dass ich falsch liege: P. Wenn Sie über das Zwischenspeichern sprechen, müssen Sie nur zwischenspeichern, wenn der Server Nein sagt. Ich meine, wenn der Server einmal Ja gesagt hat, kann man das nicht zwischenspeichern, oder?
Jesus Rodriguez
3
Ich möchte nur hinzufügen , dass es ist möglich , den Zugriff auf Verschlussgrößen im Browser (wie im Modul Muster Ihr erwähnt), insbesondere mit einem Debugger :)
Benjamin Grünbaum
2
@BenjaminGruenbaum: Fühlen Sie sich frei, dies zu einer Antwort zu erweitern, die sich auf die JS-Seite der Dinge konzentriert. Ich habe hier nur den hochrangigen, technologieunabhängigen Überblick gegeben. Eine Antwort, die sich auf JS selbst konzentriert, wäre auch nett!
Joachim Sauer
1
Kurz gesagt, wenn einige Informationen / Routen / alles, worauf zugegriffen werden kann, von einer JavaScript-Variablen abhängen, ist dies in keinem Fall sicher, da Sie diese Variable einfach ändern können, um anzugeben, was Sie für den Zugriff auf diese privaten Inhalte benötigen.
Jesus Rodriguez
4
@JoachimSauer Ich denke, das würde den Punkt dieser Frage verfehlen, den du schön genagelt hast. Unabhängig davon, welche Sicherheitsmaßnahmen der Client ergreift, kann die Kommunikation beeinträchtigt werden . Sie können sehr solide Authentifizierungssysteme in JavaScript erstellen, aber es ist alles nichts wert, sobald Sie die Kommunikation mit einem Server einfügen, den auch andere Clients als Quelle der Wahrheit betrachten. Der Quellcode wird vollständig an den Client gesendet, ein intelligenter Angreifer kann ihn nur lesen und eine HTTP-Anforderung an den Server imitieren. Man muss alles, was vom Client stammt, als nicht vertrauenswürdig behandeln, es sei denn, es wurde auf dem Server validiert.
Benjamin Gruenbaum
10

In der Gaming-Community gibt es ein Sprichwort: " Der Kunde ist in den Händen des Feindes". Jeder Code, der außerhalb eines gesicherten Bereichs wie dem Server ausgeführt wird, ist anfällig. Im einfachsten Szenario ist es anfällig, dass er nicht an erster Stelle ausgeführt wird. Es ist die Entscheidung des Kunden, Ihren" Sicherheitscode "tatsächlich auszuführen, und der Benutzer kann dies Während Sie mit nativem Code mindestens eine automatische Verschleierung in Assembler und eine zusätzliche Schutzebene haben, da ein Angreifer ein guter Programmierer sein muss, um dies zu manipulieren, wird JS normalerweise unbefleckt und als einfacher Text geliefert. Alles, was Sie zum Ausführen eines Angriffs benötigen, sind einfache Tools wie ein Proxy-Server und ein Texteditor. Der Angreifer benötigt zwar noch eine gewisse Programmierkenntnis, es ist jedoch einfacher, ein Skript mit einem Texteditor zu ändern, als Code in eine ausführbare Datei einzufügen.

nvoigt
quelle
Die Versammlung ist keine Verschleierung, und wer glaubt, dass sonst noch nie ein Kriegsspiel gespielt hat
miniBill
@miniBill: Während ein mäßig erfahrener Angreifer keine Probleme mit zusammengesetztem Code hat, bietet er einen sehr einfachen Hochpassfilter. (Leider ist dies akademisch, da das
Herausfiltern der Skriptkinder
1

Hier geht es nicht darum, JavaScript zu hacken. Wenn ich Ihre App angreifen wollte, würde ich einen privaten Proxy verwenden, mit dem ich Datenverkehr erfassen, ändern und wiedergeben kann. Ihr vorgeschlagenes Sicherheitsschema scheint keine Schutzmechanismen zu haben.

Mark E. Haase
quelle
0

Apropos Angular:

Der Schutz einer Route-Client-Seite existiert einfach nicht. Auch wenn Sie eine Schaltfläche für diese Route "verstecken", kann der Benutzer sie immer eingeben. Angular wird sich beschweren, aber der Client kann dies umgehen.

Irgendwann muss Ihr Controller Ihren Server nach den Daten fragen, die zum Rendern der Ansicht benötigt werden. Wenn der Benutzer nicht zum Zugriff auf diese Daten berechtigt ist, erhält er diese nicht, da Sie diese Daten auf der Serverseite geschützt haben und Ihre Angular-App sollte den 401 entsprechend handhaben.

Wenn Sie versuchen, die Rohdaten zu schützen, können Sie nicht auf Client-Seite, wenn Sie möchten, dass nur ein bestimmter Benutzer allgemeine Daten auf eine bestimmte Weise anzeigen kann, erstellen Sie die Datenansichten auf dem Server, anstatt sie zu senden Rohdaten an den Client senden und neu organisieren lassen (aus Performancegründen sollten Sie dies ohnehin schon tun).

Randnotiz: In Ansichtsvorlagen, die Angular anfordert, sollte niemals etwas Vertrauliches eingebaut sein. Tun Sie es einfach nicht. Wenn es einen verrückten Grund gibt, müssen Sie diese Ansichtsvorlagen auf der Serverseite genauso schützen, wie Sie es tun würden, wenn Sie serverseitig rendern würden.

Kennzeichen
quelle