Description originale du plugin
| Résumé | Discourse Encrypt permet des messageries privées et chiffrées entre utilisateurs finaux. Toutes les informations sensibles sont stockées de manière sécurisée sur le serveur et ne sont chiffrées ou déchiffrées que côté client. | |
| Lien vers le dépôt | https://github.com/discourse/discourse-encrypt | |
| Guide d’installation | Comment installer des plugins dans Discourse |
Trois étapes simples pour utiliser ce plugin
- Activez le chiffrement et activez l’appareil actuel.
- Envoyez un message chiffré. Le destinataire doit également avoir activé le chiffrement.
Optionnellement, vous pouvez déterminer le délai après lequel l’ensemble du message ou un message spécifique sera définitivement détruit.
- Lisez les messages secrets. Le chiffrement doit d’abord être activé pour les lire.
Note : Dans cet exemple, l’utilisateur a été à nouveau invité à saisir la clé papier car le chiffrement avait été désactivé (en se déconnectant ou en le désactivant explicitement depuis l’écran des préférences).
Informations techniques
Ce plugin permet aux utilisateurs de communiquer de manière sécurisée via Discourse en utilisant un système de chiffrement de bout en bout. La majeure partie de la logique du plugin est implémentée côté client, tandis que le serveur ne gère que les informations publiques ou chiffrées. Il ne chiffre aucune métadonnée de message, telle que les noms des participants à la conversation, l’heure d’envoi, les « j’aime », les petites actions, etc. Les fichiers joints sont chiffrés, mais leur présence ne l’est pas, car le système doit associer les fichiers joints aux messages pour empêcher leur suppression.
L’intégralité du code est open-source et les passionnés de sécurité sont les bienvenus pour l’examiner. Pour toute information complémentaire, n’hésitez pas à me contacter ou à contacter l’équipe. ![]()
lire plus...
Résumé
L’objectif de ce plugin est d’assurer l’intégrité et la confidentialité des contenus chiffrés, et de les protéger contre les fuites d’informations et les utilisateurs non autorisés. Les sections suivantes décrivent le mode de fonctionnement habituel, les algorithmes utilisés et les modèles de menaces.
Pour utiliser ce système, les utilisateurs s’inscrivent une fois en générant une « identité utilisateur » composée de deux clés RSA de 4096 bits, l’une pour le chiffrement et l’autre pour la signature. Les utilisateurs peuvent exporter leur « identité » pour la conserver en sécurité ou la stocker sur le serveur, chiffrée après la génération d’une clé papier. Ces deux méthodes servent de sauvegardes ou sont utilisées pour inscrire de nouveaux appareils.
Les clés papier (inspirées de RFC 1751 et BIP-39) sont des clés lisibles par l’homme utilisées pour stocker de manière sécurisée l’« identité utilisateur » sur le serveur. Une clé papier se compose de 12 mots aléatoires, choisis dans une liste de 2048 mots, offrant 121 bits d’entropie (le premier mot est utilisé comme étiquette). Pour chiffrer l’« identité utilisateur » avec une clé papier, le système dérive d’abord la clé de chiffrement en utilisant PBKDF2 pour étirer la clé papier en une clé AES-GCM de 256 bits.
Création d’un message chiffré
Pour créer un nouveau message, l’utilisateur (son navigateur) va :
-
signer le contenu actuel du message à l’aide de sa clé privée de signature ;
-
générer une nouvelle « clé de sujet » (une clé AES-256-GCM) qui sera utilisée pour chiffrer le message, certaines métadonnées du message et le titre du nouveau sujet (si disponible) ;
-
récupérer les clés publiques de tous les participants et chiffrer la « clé de sujet » pour chacun d’eux ;
-
envoyer au serveur le message chiffré (encodé en Base64) et les clés de sujet chiffrées (également encodées en Base64) de chaque participant.
Le pseudocode pour l’opération de chiffrement serait quelque chose comme :
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
Lecture d’un message chiffré
Pour lire un message, l’utilisateur (son navigateur) va :
-
récupérer la charge utile du message chiffré (texte brut du message et signature) et la clé de sujet chiffrée ;
-
utiliser sa clé privée de chiffrement pour déchiffrer la clé de sujet chiffrée ;
-
utiliser la clé de sujet déchiffrée pour déchiffrer la charge utile du message chiffré ;
-
récupérer la clé publique de signature de l’auteur et vérifier la signature du message.
Suite d’algorithmes
Ce plugin utilise largement les primitives cryptographiques implémentées dans l’API Web Crypto, disponibles dans tous les navigateurs modernes pris en charge par Discourse (sauf Internet Explorer).
-
getRandomValuesPRNG: Génère des clés papier et des vecteurs d’initialisation (IV) aléatoires de 96 bits. -
PBKDF2: Étire les clés papier de 132 bits en clés de 256 bits, utilisées pour chiffrer les « identités utilisateur ».
-
AES-256-GCM: Utilisé pour chiffrer le contenu de chaque message. Il offre également une authentification en produisant une étiquette d’authentification de 128 bits, mais cet aspect est moins important car les messages sont vérifiés à l’aide d’une signature générée par l’auteur (voir étape 1 ci-dessus).
-
RSA-OAEP: Utilisé pour chiffrer les « clés de sujet » et les « identités utilisateur » pour un stockage sécurisé sur le serveur. Toutes les clés RSA-OAEP font 4096 bits de long.
-
RSA-PSS: Utilisé pour signer le contenu de chaque message afin de vérifier son authenticité. Toutes les clés RSA-PSS font 4096 bits de long.
Primitives
Le système utilise un ensemble de primitives construites sur celles fournies par le navigateur via l’API de cryptographie Web.
-
encrypt et decrypt: Utilisés pour chiffrer et déchiffrer le contenu des messages.
encryptprend un JSON, une clé AES-256-GCM et une clé publique RSA-PSS, et produit une seule chaîne encodée en Base64 ;decryptprend une chaîne encodée en Base64 et une clé AES-256-GCM, et produit l’objet JSON initial ; -
verify: Utilisé pour vérifier le contenu des messages après déchiffrement ;
-
exportKey et importKey: Utilisés pour exporter et importer les « clés de sujet » ;
-
exportIdentity et importIdentity: Utilisés pour exporter et importer les « identités utilisateur ».
Types de clés :
-
clés de sujet (AES-256-GCM)
- utilisées pour chiffrer chaque message d’un sujet (les messages sont chiffrés individuellement)
- sont générées par sujet, côté client, par l’auteur original en utilisant la primitive
generateKeyde l’API WebCrypto - sont chiffrées avec la clé publique de l’utilisateur pour chaque utilisateur ayant accès au sujet spécifique, en utilisant la primitive
wrapKeyde l’API WebCrypto - sont stockées (chiffrées) côté serveur pour chaque utilisateur dans
PluginStore
-
paires de clés RSA (clés publique et privée) (RSA-OAEP et RSA-PSS, 4096 bits)
- utilisées pour chiffrer toutes les clés de sujet auxquelles un utilisateur a accès
- sont générées par utilisateur, côté client, par l’auteur original en utilisant la primitive
generateKeyde l’API WebCrypto et partagées entre tous les appareils de l’utilisateur - côté serveur: l’identité publique est stockée telle qu’exportée par le client, mais l’identité privée sera toujours chiffrée avec la clé de phrase de passe
- côté client: les clés publique et privée sont stockées sous forme de
CryptoKeydans IndexedDb ; si cela n’est pas possible,window.localStoragesera utilisé (dans Safari)
-
clés de phrase de passe (dérivées en utilisant PKBDF2 avec 128 000 itérations)
- utilisées pour chiffrer les « identités utilisateur » pour un stockage sécurisé sur le serveur
- dérivées d’une clé papier (ou de la phrase de passe de l’utilisateur à des fins de compatibilité)
Modèles de menaces
Instance Discourse compromise
Un attaquant capable d’injecter du code pourrait théoriquement accéder aux informations chiffrées en servant du code malveillant, qui déchiffre le contenu chiffré et envoie les messages en clair à un autre serveur. Pour rendre cela possible, il suffit d’avoir accès à un compte administrateur et de créer un composant de thème contenant le code malveillant.
Les mécanismes de protection par défaut, tels que CSP, peuvent détecter et atténuer les attaques par injection de scripts inter-sites (XSS) qui pourraient également constituer un moyen d’injecter du code malveillant.
Attaque de l’homme du milieu
Dans les attaques de l’homme du milieu, l’attaquant intercepte la communication entre l’utilisateur et le serveur, lui permettant de la lire ou de la modifier. Comme le plugin chiffre tout avant l’envoi, un attaquant ne peut rien déchiffrer en écoutant simplement. De même, comme les informations sont authentifiées, l’attaquant ne peut pas les modifier.
Cependant, l’attaquant pourrait servir du code malveillant à l’utilisateur et suivre une attaque similaire à celle présentée dans la section précédente. Cela est partiellement atténué par HTTPS, qui réduit considérablement la probabilité d’attaque.
Notes
Le plugin a déjà une petite histoire, ce qui peut être constaté en parcourant le code source et en remarquant les deux implémentations du protocole v0 (initial, version alpha-bêta) et v1. Le protocole v0 n’est plus utilisé pour chiffrer de nouveaux messages, mais est conservé pour continuer à déchiffrer les anciens. Le nouveau protocole inclut l’authenticité des textes chiffrés et tous les messages sont signés avec la clé privée de l’auteur.
