it-swarm.com.de

Was ist mit der Kryptografie im Browser im Jahr 2017 falsch?

Es gibt viele Artikel im Internet, die die JavaScript-Kryptographie im Browser kritisieren:

Sie sprechen einige faire Punkte an, aber ich werde sie gerne aus der Perspektive von 2017 analysieren und Ihre Meinung kennen. Dazu definiere ich eine mögliche Architektur für eine verschlüsselte Notizen-Site, damit Sie mögliche Probleme und Lösungen in Bezug auf den Sicherheitsaspekt ansprechen können:

  1. Natürlich werden wir SSL verwenden.

  2. Wenn sich ein Benutzer zum ersten Mal in unserer Notizen-App anmeldet, senden wir ihm unseren öffentlichen Schlüssel. Dieser Schlüssel wird verwendet, um die Authentizität unseres Skripts crypto.js Zu überprüfen. Der öffentliche Schlüssel wird im Browser des Benutzers gespeichert.

  3. Ein checker.js - Skript wird ebenfalls heruntergeladen und gespeichert. Dieses Skript wird sich nie ändern und die Integrität von crypto.js Und (2) überprüfen.

  4. In (2) und (3) stellen wir eine TOFU-Beziehung (Trust On First Use) zwischen dem Benutzer und unserer Website her. Sowohl der öffentliche Schlüssel als auch checker.js Werden mit einem Servicemitarbeiter oder ähnlichem zwischengespeichert. Wir werden auch [~ # ~] sri [~ # ~] verwenden, um zu versuchen, die Integrität zu maximieren.

  5. Obwohl wir SSL verwenden, kann beim Herunterladen von (2) und (3) ein MITM-Angriff auftreten, sodass wir eine Möglichkeit bieten können, zu überprüfen, ob der öffentliche Schlüssel und checker.js Nicht gefährdet sind. Zum Beispiel durch Vergleichen der Hashes der lokalen Kopie von (2) und (3) mit den realen auf unserer Site oder einer Site eines Drittanbieters. Diese Lösung ist nicht perfekt und dies ist wahrscheinlich das schwache Glied, aber ich glaube, dass ein ähnlicher Angriff auf Desktop-Apps durchgeführt werden könnte.

  6. Beim ersten Login senden wir dem Benutzer auch seinen privaten Schlüssel. Dieser private Schlüssel wird zum Verschlüsseln und Signieren der Notizen verwendet. Dieser private Schlüssel wird verschlüsselt.

  7. Der zum Entschlüsseln erforderliche Schlüssel (6) wird per E-Mail an den Benutzer gesendet. Auf diese Weise stellen wir eine Zweikanalauthentifizierung her.

  8. Mit Web Crypto entschlüsseln wir (6) mit (7). Auf diese Weise wird (6) niemals entschlüsselt im Browser gespeichert und ist dank der Web Crypto API für JavaScript nicht zugänglich.

  9. Jetzt können wir mit der Funktionalität unserer Web-App beginnen: Erstellen Sie verschlüsselte Notizen. Dazu schreibt der Benutzer eine Notiz und klickt auf die Schaltfläche Speichern. Der Server sendet crypto.js Signiert mit dem privaten Schlüssel des Servers (siehe 2).

  10. Die Signatur wird mit dem in (2) mit (3) heruntergeladenen öffentlichen Schlüssel überprüft. Wenn dies korrekt ist, wird die Notiz verschlüsselt. Wenn checker.js Geändert wurde, sollte SRI diesen Prozess stoppen.

  11. Die Notiz wird an den Server zurückgesendet und gespeichert.

  12. Abhängig von der erforderlichen Funktionalität sollte der Server den privaten Schlüssel des Benutzers löschen und nur den öffentlichen behalten oder nicht.

Was denkst du über dieses Setup?

Ich bin nicht glücklich über (5), aber dies kann mit nativer Software passieren. Es ist nicht das erste Mal, dass Installationsprogramme kompromittiert werden . Auch ein MITM beim Herunterladen des Installationsprogramms kann auftreten. Und die native Codesignatur ist nicht perfekt .

Denken Sie, dass Web-Krypto immer noch strikt schlechter ist als native Krypto?

Irgendwelche Vorschläge, die die Kryptographie des Browsers verbessern könnten?

19
user1204395

Das Hauptproblem bei der Kryptografie auf Webseiten besteht darin, dass dieser Server, da der von Ihnen ausgeführte Code von einem Webserver geladen wird, die volle Kontrolle über diesen Code hat und ihn bei jeder Aktualisierung der Seite ändern kann. Wenn Sie den Code, den Sie ausführen, nicht jedes Mal manuell überprüfen, wenn Sie eine neue Seite auf dieser Site laden (vorzugsweise bevor dieser Code tatsächlich ausgeführt wird), können Sie nicht wissen, was dieser Code tatsächlich tut.

Die Web-Kryptografie-API kann das Risiko etwas verringern, indem sie kryptografische Schlüssel so sicher speichert, dass auf der Seite ausgeführte Skripts nicht zugreifen können, aber alle Vorgänge, die mit diesen Schlüsseln ausgeführt werden können (Entschlüsseln, Signieren usw.), bleiben bestehen verfügbar für diese (möglicherweise böswilligen) Skripte.

Solange Sie do darauf vertrauen, dass sich der Server nicht böswillig verhält, kann Kryptografie im Browser sehr nützlich sein. In vielen Anwendungen, in denen Kryptografie verwendet wird, ist diese Vertrauensstufe in einen Remoteserver jedoch nicht von Ihnen gesteuert ist inakzeptabel.

Insbesondere für Ihr Programm:

  1. Natürlich werden wir SSL verwenden

Das ist gut. Ohne SSL wären alle späteren Sicherheitsmaßnahmen sinnlos, da ein Angreifer Ihren Code einfach durch seinen eigenen ersetzen und mit den Daten des Benutzers tun könnte, was er will.

  1. Wenn sich ein Benutzer zum ersten Mal in unserer Notizen-App anmeldet, senden wir ihm unseren öffentlichen Schlüssel. Dieser Schlüssel wird verwendet, um die Authentizität unseres Skripts "crypto.js" zu überprüfen. Der öffentliche Schlüssel wird im Browser des Benutzers gespeichert.

Das scheint sinnlos. TLS bereits sendet dem Client den öffentlichen Schlüssel Ihres Servers und verwendet ihn, um die Authentizität von all Skripten zu überprüfen, die Sie über diese Verbindung laden. Es gibt keinen Grund, dasselbe in JavaScript noch einmal zu tun.

  1. Ein "checker.js" -Skript wird ebenfalls heruntergeladen und gespeichert. Dieses Skript wird sich nie ändern und die Integrität von "crypto.js" und (2) überprüfen.

Dies ist auch sinnlos, da es keine Möglichkeit gibt, Ihre Anforderung "Dieses Skript wird sich nie ändern" durchzusetzen. Sie könnten einen Cache-Control-Header mit einem langen Höchstalter senden, es gibt jedoch keine Garantie dafür, dass der Benutzeragent diesen Wert immer respektiert. Caching ist aus Sicherheitsgründen nicht als verlässlich anzusehen.

  1. In (2) und (3) stellen wir eine TOFU-Beziehung (Trust On First Use) zwischen dem Benutzer und unserer Website her. Sowohl der öffentliche Schlüssel als auch "checker.js" werden mithilfe eines Servicemitarbeiters oder ähnlichem zwischengespeichert.

Um ganz klar zu sein: Das Zwischenspeichern dieser Dateien mit Servicemitarbeitern hat keine Auswirkungen auf die Sicherheit des Gesamtsystems. Wenn der Benutzer später zu Ihrer Site zurückkehrt, überprüft der Browser beim Server, ob der Servicemitarbeiter die neue Version aktualisiert hat, und installiert sie gegebenenfalls. Der Server hat also weiterhin die volle Kontrolle über den Code, der im Browser des Benutzers ausgeführt wird. Hier gibt es keine "Trust On First Use (TOFU) -Beziehung".

  1. Obwohl wir SSL verwenden, kann beim Herunterladen von (2) und (3) ein MITM-Angriff auftreten, sodass wir eine Möglichkeit bieten können, zu überprüfen, ob der öffentliche Schlüssel und "checker.js" nicht gefährdet sind.

Das ist eine nette Geste, aber wie ich bereits sagte, können der Server oder ein MITM (der es irgendwie geschafft hat, Ihre TLS-Verbindung zu gefährden) diese Dateien jederzeit problemlos aktualisieren, um sie zu kompromittieren, ohne dass der Benutzer es bemerkt. Daher verstehe ich den Sinn dieser Funktion nicht wirklich.

  1. Beim ersten Login senden wir dem Benutzer auch seinen privaten Schlüssel. Dieser private Schlüssel wird zum Verschlüsseln und Signieren der Notizen verwendet. Dieser private Schlüssel wird verschlüsselt.

  2. Der zum Entschlüsseln erforderliche Schlüssel (6) wird per E-Mail an den Benutzer gesendet. Auf diese Weise stellen wir eine Zweikanalauthentifizierung her.

  3. Mit Web Crypto ( https://www.w3.org/TR/WebCryptoAPI/ ) entschlüsseln wir (6) mit (7). Auf diese Weise wird (6) niemals entschlüsselt im Browser gespeichert und ist dank der Web Crypto API für JavaScript nicht zugänglich.

Um dies zu implementieren, muss der Server Zugriff auf eine Klartextversion des privaten Schlüssels des Benutzers haben. Je nachdem, wofür Sie diese Schlüssel verwenden, kann dies problematisch sein, wenn der Server jemals kompromittiert wird. Stattdessen sollten Sie die Verwendung der Web Crypto-API in Betracht ziehen, um ein privat-öffentliches Schlüsselpaar auf dem Gerät des Benutzers zu generieren, und den Browser den öffentlichen Teil dieses Schlüssels an den Server senden lassen. Auf diese Weise hat der Server niemals Zugriff auf den privaten Schlüssel des Benutzers.

  1. Jetzt können wir mit der Funktionalität unserer Web-App beginnen: Erstellen Sie verschlüsselte Notizen. Dazu schreibt der Benutzer eine Notiz und klickt auf die Schaltfläche Speichern. Der Server sendet "crypto.js", das mit dem privaten Schlüssel des Servers signiert ist (siehe 2).

  2. Die Signatur wird mit dem in (2) mit (3) heruntergeladenen öffentlichen Schlüssel überprüft. Wenn dies korrekt ist, wird die Notiz verschlüsselt. Wenn "checker.js" geändert wurde, sollte SRI diesen Prozess stoppen.

Sofern Sie checker.js Nicht von einem nicht vertrauenswürdigen Server eines Drittanbieters laden, ist Subresource Integrity in diesem Szenario nicht erforderlich. Jeder, der Ihren Server oder seine Verbindung zum Client gefährden kann, um checker.js Zu ändern, kann auch die Werte der Subressourcen-Integritäts-Hashes ändern, sodass der Browser das geänderte Skript ohne Beanstandung akzeptiert. Oder sie können die Seite einfach so ändern, dass checker.js Überhaupt nicht geladen wird, und stattdessen ein völlig anderes Skript verwenden, das sie selbst erstellt haben. In beiden Fällen hilft die Integrität der Subressourcen nicht weiter.

  1. Die Notiz wird an den Server zurückgesendet und gespeichert.

Das ist in Ordnung, solange Sie das bereits erwähnte Problem mit 6, 7 und 8 beheben, sodass der Server nicht über die Schlüssel verfügt, die zum Entschlüsseln der Benutzerdateien erforderlich sind. Wenn der Server über die Schlüssel für den Zugriff auf die Benutzerdateien verfügt, ist keine clientseitige Krypto erforderlich. Lassen Sie einfach den Server die Verschlüsselung übernehmen.

  1. Abhängig von der erforderlichen Funktionalität sollte der Server den privaten Schlüssel des Benutzers löschen und nur den öffentlichen behalten oder nicht.

Oder, wie ich vorgeschlagen habe, geben Sie dem Server überhaupt nicht den Benutzerschlüssel. Davon abgesehen ist dieser Teil in Bezug auf die Sicherheit in Ordnung, da er verhindert, dass der Server auf die Dateien des Benutzers zugreift, während der Benutzer die Site nicht verwendet.

Sobald der Benutzer die Site besucht, lädt der Browser des Benutzers Code von diesem Server, der die Schlüssel des Benutzers zum Entschlüsseln der Notizen des Benutzers verwenden kann. Für den durchschnittlichen Benutzer ist es daher unmöglich, auf seine Notizen zuzugreifen, ohne dass Ihr Server sie lesen kann.

Es gibt auch einige Usability-Probleme bei dieser Implementierung, da Benutzer sich nicht über einen neuen Browser in ihrem Konto anmelden können und dennoch Zugriff auf ihre Notizen haben. Eine bessere Implementierung wäre, die Kryptoschlüssel der Benutzer aus ihren Passwörtern mithilfe eines Schlüsselableitungsalgorithmus wie PBKDF2 (verfügbar über die Web Cryptography API) mit einem hohen Arbeitsfaktor abzuleiten. Dies würde es ihnen ermöglichen, von jedem Browser aus auf ihre Notizen zuzugreifen. (Hätte aber immer noch die gleichen Sicherheitsnachteile, die in meinen obigen Kommentaren erwähnt wurden.)

9
Ajedi32

Die Dinge, die mir wirklich auffallen, sind 6 und 7. Dies ist bei weitem das, was mich an dieser Beschreibung am meisten erschreckt.

Der gesamte Sinn der Einrichtung von TOFU besteht darin, dass es wechselseitiges Vertrauen gibt. Natürlich hat das Vertrauen bei der ersten Verwendung seine eigenen Probleme, und ich glaube, Sie haben bereits dargelegt, dass die meisten dieser Fälle, obwohl sie weniger wahrscheinlich auftreten, möglich sind.

Aber Sie sagen mir, die Site generiert einen privaten Schlüssel für mich und gibt mir diesen verschlüsselten Schlüssel. Dann kann ich einen privaten Schlüssel entschlüsseln Schlüssel per E-Mail? Senden Sie mir im Grunde eine Möglichkeit, meine Art der Entschlüsselung per E-Mail zu entschlüsseln.

Ich meine, wenn ich einen Dienst benutze, suche ich im Allgemeinen nach gleicher Belichtung. Ich möchte nicht, dass die Website der einzige Fehlerpunkt für alles ist, was ich tue. Es entsteht auch eine Situation, in der Nachrichten, die für mich bestimmt sind, von jedem entschlüsselt werden können, der über Systemadministratorzugriff auf die vom Benutzer generierten privaten Schlüssel verfügt. Was bedeutet, dass ich ihm nicht vertrauen kann.

Es untergräbt den ganzen Punkt der asymmetrischen Kryptographie vollständig. Zumal das Erstellen meines eigenen privaten Schlüssels und das Senden des Servers an den Server eine einfache Angelegenheit ist. Selbst für Benutzer, die technisch nicht geneigt sind, könnte es in den Client aufgenommen werden. Es gibt absolut keinen Grund für eine andere Partei, einen privaten Schlüssel für mich IMO zu erstellen oder für diesen Schlüssel jemals das Internet zu berühren.

Ich werde andere die anderen Punkte beantworten lassen, ich denke, 6 und 7 sind die gefährlichsten. Mit Ausnahme von MITM, das Sie bereits im OP erwähnt haben.

7
Nalaurien

Der einzige Kontext, in dem ich clientseitige Kryptografie durchführe, ist das Hashing von Client-Anmeldeinformationen (Kennwort, Kreditkarteninformationen usw.), damit der Server sie nicht kennt. Ja, der Server muss das einfache Kennwort nicht kennen, das er auf Gültigkeit prüfen muss. Der Server wendet ein eigenes Hashing auf die empfangene Pasword-Zeichenfolge an. Solange der Client denselben Hash sendet, funktioniert das Schema einwandfrei. Ein gültiges Kennwort wird authentifiziert, während der Server nicht mit dem einfachen Kennwort-/Client-Hashing-Algorithmus des Clients vertraut ist. Ich habe in der Vergangenheit Benutzernamen verschlüsselt/entschlüsselt, als einige unserer Kunden unserer Empfehlung, das System auf https/tls zu implementieren, nicht Folge geleistet haben. Das Verschlüsseln/Entschlüsseln von Benutzernamen ist bei der SSL-Kommunikation sinnlos, da der Server den Benutzernamen kennt/speichert. Was meine ich? Ich empfehle keine clientseitige Krypto, solange der Kontext den Server nicht unabhängig von den geheimen Daten des Clients macht. Es dient dazu, das Client-Geheimnis vor dem Server zu schützen oder den Server vor einer Sicherheitslücke von heiligem Ausmaß zu schützen. In allen anderen Kontexten nicht von der Hauptstraße abweichen (https, tls usw.)

P.S. Einige Benutzer sind dumm, Wörter in ihren Benutzernamen in ihren Passwörtern zu verwenden, wenn es um Datensatzverwaltung und Dokumentenverwaltungskontexte geht. Mein Lieblingsangriff ist das Timing-Angriff auf Benutzernamen und die Verwendung von Benutzernamen als wertvolle Ressource für Wörterbuchangriffe auf Kennwörter, wenn der Timing-Angriff auf Kennwörter direkt fehlschlägt. Es ist interessant zu sehen, dass sich nur wenige Menschen in der Welt der Entwickler von Dokumenten-/Datensatzverwaltungssoftware für das Timing von Angriffen auf Benutzernamen interessieren.

0
Ersin TASKIN