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?
quelle
manipulate any part of the sight without long lines
site vs sightAntworten:
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
prompt
und 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:
quelle
window.prompt
Methode ü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.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.
quelle
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.
quelle
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.
quelle
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.
quelle