Original Plugin-Beschreibung
| Zusammenfassung | Discourse Encrypt ermöglicht private, verschlüsselte Nachrichten zwischen Endbenutzern. Alle sensiblen Informationen werden sicher auf dem Server gespeichert und nur auf der Client-Seite verschlüsselt und entschlüsselt. | |
| Repository-Link | https://github.com/discourse/discourse-encrypt | |
| Installationsanleitung | So installieren Sie Plugins in Discourse |
Drei einfache Schritte zur Verwendung dieses Plugins
- Verschlüsselung aktivieren und aktuelles Gerät aktivieren.
- Eine verschlüsselte Nachricht senden. Der Empfänger muss ebenfalls die Verschlüsselung aktiviert haben.
Optional können Sie die Zeit festlegen, nach der die gesamte Nachricht oder ein bestimmter Beitrag dauerhaft gelöscht wird.
- Geheime Nachrichten lesen. Die Verschlüsselung muss zuerst aktiviert sein, um sie lesen zu können.
Hinweis: In diesem Beispiel wurde der Benutzer erneut nach dem Papier-Schlüssel gefragt, da die Verschlüsselung deaktiviert wurde (durch Abmelden oder explizites Deaktivieren im Einstellungsbildschirm).
Technische Informationen
Dieses Plugin bietet Benutzern die Möglichkeit, über Discourse sicher zu kommunizieren, indem ein End-to-End-Verschlüsselungsverfahren verwendet wird. Der Großteil der Plugin-Logik wird auf der Client-Seite implementiert, und der Server verarbeitet nur öffentliche oder verschlüsselte Informationen. Es werden keine Metadaten von Beiträgen verschlüsselt, wie z. B. Namen der Teilnehmer im Gespräch, Zeitpunkt des Postens, Likes, kleine Aktionen usw.; Uploads werden verschlüsselt, aber ihre Existenz nicht, da das System Uploads mit Beiträgen verknüpfen muss, um deren Löschung zu verhindern.
Der gesamte Code ist Open-Source, und Sicherheitsenthusiasten sind willkommen, ihn zu überprüfen. Für weitere Informationen zögern Sie nicht, mich oder das Team zu kontaktieren. ![]()
mehr lesen...
Zusammenfassung
Das Ziel dieses Plugins ist es, Integrität und Vertraulichkeit der verschlüsselten Inhalte zu gewährleisten und sie vor Informationslecks und unbefugten Benutzern zu schützen. Die folgenden Abschnitte beschreiben den üblichen Betriebsmodus, verwendete Algorithmen und Bedrohungsmodelle.
Um dieses System zu verwenden, registrieren sich Benutzer einmalig, indem sie eine „Benutzeridentität“ generieren, die aus zwei 4096-Bit-RSA-Schlüsseln besteht, einem für die Verschlüsselung und einem für die Signatur. Benutzer können ihre „Identität“ zur sicheren Aufbewahrung exportieren oder auf dem Server speichern, nachdem sie einen Papier-Schlüssel generiert haben. Diese beiden Methoden dienen als Sicherungskopien oder werden zur Registrierung neuer Geräte verwendet.
Papier-Schlüssel (inspiriert von RFC 1751 und BIP-39) sind menschenlesbare Schlüssel, die verwendet werden, um die „Benutzeridentität“ sicher auf dem Server zu speichern. Ein Papier-Schlüssel besteht aus 12 zufälligen Wörtern, die aus einer Liste von 2048 Wörtern ausgewählt werden, und bietet 121-Bit-Entropie (das erste Wort wird als Beschriftung verwendet). Um die „Benutzeridentität“ mit einem Papier-Schlüssel zu verschlüsseln, leitet das System zunächst den Verschlüsselungsschlüssel mithilfe von PBKDF2 ab, um den Papier-Schlüssel in einen 256-Bit-AES-GCM-Schlüssel zu strecken.
Erstellen eines verschlüsselten Beitrags
Um einen neuen Beitrag zu erstellen, führt der Benutzer (sein Browser) folgende Schritte aus:
-
Signieren Sie den aktuellen Beitrag mit Ihrem privaten Signierschlüssel;
-
Generieren Sie einen neuen „Topic-Schlüssel“ (einen AES-256-GCM-Schlüssel) – dieser wird verwendet, um den Beitrag, einige Beitragsmetadaten und den Titel des neuen Topics (falls verfügbar) zu verschlüsseln;
-
Holen Sie sich die öffentlichen Schlüssel aller Teilnehmer und verschlüsseln Sie den „Topic-Schlüssel“ für jeden von ihnen;
-
Senden Sie den verschlüsselten Beitrag (Base64-kodiert) und die verschlüsselten Topic-Schlüssel (ebenfalls Base64-kodiert) jedes Teilnehmers an den Server.
Der Pseudocode für den Verschlüsselungsvorgang könnte wie folgt aussehen:
signature = rsa_pss_sign(current_user.identity.sign_key.private, post.raw) # 1
topic_key = topic.key || generate_aes_256_gcm_key() # 2
encrypted_title = aes_256_gcm_encrypt(topic.title, topic_key) if topic.blank?
encrypted_post = aes_256_gcm_encrypt(signature + post.raw, topic_key)
encrypted_topic_keys = recipients.map { |r| rsa_oaep_encrypt(topic_key, r.identity.encryption_key.public) } # 3
$.put("/posts/create", { title: encrypted_title, raw: encrypted_post, keys: encrypted_topic_keys }) # 4
Lesen eines verschlüsselten Beitrags
Um einen Beitrag zu lesen, führt der Benutzer (sein Browser) folgende Schritte aus:
-
Holen Sie sich den verschlüsselten Beitrag (Beitragstext und Signatur) und den verschlüsselten Topic-Schlüssel;
-
Verwenden Sie Ihren privaten Verschlüsselungsschlüssel, um den verschlüsselten Topic-Schlüssel zu entschlüsseln;
-
Verwenden Sie den entschlüsselten Topic-Schlüssel, um den verschlüsselten Beitragstext zu entschlüsseln;
-
Holen Sie sich den öffentlichen Signierschlüssel des Autors und überprüfen Sie die Beitragssignatur.
Algorithmus-Suite
Dieses Plugin verwendet intensiv die kryptografischen Primitive, die in der Web Crypto API implementiert sind, die in allen modernen Browsern verfügbar sind, die Discourse unterstützt (außer Internet Explorer).
-
getRandomValuesPRNG: Generiert Papier-Schlüssel und 96-Bit-zufällige IVs. -
PBKDF2: Streckt die 132-Bit-Papier-Schlüssel auf 256-Bit-Schlüssel, die zum Verschlüsseln von „Benutzeridentitäten“ verwendet werden.
-
AES-256-GCM: Wird verwendet, um den Inhalt jedes Beitrags zu verschlüsseln. Es bietet auch Authentifizierung durch Erstellen eines 128-Bit-Authentifizierungstags, aber dies ist ein weniger wichtiger Aspekt, da Beiträge mit einer Signatur des Autors überprüft werden (siehe Schritt 1 oben).
-
RSA-OAEP: Wird verwendet, um „Topic-Schlüssel“ und „Benutzeridentitäten“ zur sicheren Aufbewahrung auf dem Server zu verschlüsseln. Alle RSA-OAEP-Schlüssel sind 4096-Bit lang.
-
RSA-PSS: Wird verwendet, um den Inhalt jedes Beitrags zu signieren, um die Authentizität zu überprüfen. Alle RSA-PSS-Schlüssel sind 4096-Bit lang.
Primitive
Das System verwendet eine Reihe von Primitiven, die auf denen aufbauen, die vom Browser über die Web Cryptography API bereitgestellt werden.
-
encrypt und decrypt: Wird verwendet, um Beitragsinhalte zu verschlüsseln und zu entschlüsseln.
encryptnimmt ein JSON, einen AES-256-GCM-Schlüssel und einen RSA-PSS-öffentlichen Schlüssel entgegen und gibt einen einzelnen Base64-kodierten String zurück;decryptnimmt einen Base64-kodierten String und einen AES-256-GCM-Schlüssel entgegen und gibt das ursprüngliche JSON-Objekt zurück; -
verify: Wird verwendet, um Beitragsinhalte nach der Entschlüsselung zu überprüfen;
-
exportKey und importKey: Wird verwendet, um „Topic-Schlüssel“ zu exportieren und zu importieren;
-
exportIdentity und importIdentity: Wird verwendet, um „Benutzeridentitäten“ zu exportieren und zu importieren.
Arten von Schlüsseln:
-
Topic-Schlüssel (AES-256-GCM)
- werden verwendet, um jeden Beitrag in einem Topic zu verschlüsseln (Beiträge werden einzeln verschlüsselt)
- werden generiert pro Topic auf der Client-Seite vom ursprünglichen Autor unter Verwendung der WebCrypto-API
generateKey-Primitive - werden mit dem öffentlichen Schlüssel des Benutzers für jeden Benutzer verschlüsselt, der Zugriff auf das spezifische Topic hat, unter Verwendung der WebCrypto-API
wrapKey-Primitive - werden gespeichert (verschlüsselt) auf der Server-Seite für jeden Benutzer in
PluginStore
-
RSA-Schlüsselpaar (öffentlicher und privater Schlüssel) (RSA-OAEP und RSA-PSS, 4096-Bit)
- werden verwendet, um alle Topic-Schlüssel zu verschlüsseln, auf die ein Benutzer Zugriff hat
- werden generiert pro Benutzer auf der Client-Seite vom ursprünglichen Autor unter Verwendung der WebCrypto-API
generateKey-Primitive und zwischen allen Geräten des Benutzers geteilt - serverseitig: Die öffentliche Identität wird so gespeichert, wie sie vom Client exportiert wurde, aber die private Identität wird immer mit dem Passphrasenschlüssel verschlüsselt
- clientseitig: Öffentlicher und privater Schlüssel werden als
CryptoKeyin IndexedDb gespeichert; falls nicht möglich, wirdwindow.localStorageverwendet (in Safari)
-
Passphrasenschlüssel (abgeleitet unter Verwendung von PKBDF2 mit 128.000 Iterationen)
- werden verwendet, um „Benutzeridentitäten“ zur sicheren Speicherung auf dem Server zu verschlüsseln
- abgeleitet aus einem Papier-Schlüssel (oder dem Passwort des Benutzers aus historischen Gründen)
Bedrohungsmodelle
Kompromittierte Discourse-Instanz
Ein Angreifer, der Code injizieren kann, könnte theoretisch auf verschlüsselte Informationen zugreifen, indem er bösartigen Code bereitstellt, der den verschlüsselten Inhalt entschlüsselt und die Klartext-Beiträge an einen anderen Server sendet. Um dies zu ermöglichen, reicht es aus, Zugriff auf ein Administratorkonto zu haben und eine Theme-Komponente mit dem bösartigen Code zu erstellen.
Standard-Schutzmechanismen wie CSP können Cross-Site-Scripting-Angriffe (XSS) erkennen und mildern, die ebenfalls eine Möglichkeit zur Injektion von bösartigem Code darstellen könnten.
Man-in-the-Middle-Angriff
Bei Man-in-the-Middle-Angriffen fängt der Angreifer die Kommunikation zwischen Benutzer und Server ab und hat dadurch die Möglichkeit, sie zu lesen oder zu verändern. Da das Plugin alles vor dem Senden verschlüsselt, kann ein Angreifer durch einfaches Abhören nichts entschlüsseln. Ebenso kann der Angreifer aufgrund der Authentifizierung der Informationen nichts verändern.
Der Angreifer könnte jedoch bösartigen Code an den Benutzer zurücksenden und einen ähnlichen Angriff wie im vorherigen Abschnitt durchführen. Dies wird teilweise durch HTTPS gemildert, was die Angriffswahrscheinlichkeit erheblich reduziert.
Hinweise
Das Plugin hat bereits eine kleine Geschichte, die beim Durchsuchen des Quellcodes und beim Erkennen der beiden Implementierungen des Protokolls v0 (initial, Alpha-Beta-Version) und v1 sichtbar wird. Das Protokoll v0 wird nicht mehr zum Verschlüsseln neuer Beiträge verwendet, aber beibehalten, um alte Beiträge weiterhin entschlüsseln zu können. Das neue Protokoll umfasst die Authentizität der Chiffretexte, und alle Beiträge werden mit dem privaten Schlüssel des Autors signiert.
