Messaggi personali crittografati

Vorremmo commissionare un plugin che consenta messaggistica privata e crittografata tra gli utenti finali.

:mega: Questo plugin esiste già ed è ufficialmente supportato; consultate Discourse Encrypt (deprecated)

Al momento, esistono pochissimi spazi online per comunicazioni private, sicure e di lunga durata. Gli strumenti esistenti sono solitamente piuttosto complessi e richiedono competenze tecniche avanzate per essere utilizzati. Di conseguenza, la maggior parte delle comunicazioni “private” avviene in forma “breve” su Telegram, Skype o WhatsApp. Inoltre, questa modalità di comunicazione di massa non è adeguatamente verificabile, poiché si basa su strumenti closed source e spesso su protocolli chiusi.

Desideriamo creare una soluzione altamente utilizzabile e verificabile per la messaggistica crittografata all’interno di un plugin dedicato per Discourse.

Per raggiungere questo obiettivo, ci baseremo sui seguenti principi:

  1. Costruire la soluzione utilizzando l’API Web Crypto.

  2. Far sì che il server memorizzi una chiave privata crittografata e una chiave pubblica per ogni utente.

  3. Far sì che il server memorizzi una chiave di conversazione crittografata per ogni partecipante alle messaggi private (crittografata utilizzando la chiave privata dell’utente finale).

  4. Memorizzare tutto il contenuto Markdown e i titoli nella forma grezza e crittografata per ogni messaggio (crittografati utilizzando la chiave di conversazione).

  5. Accettare il limite secondo cui il server conosce chi ha parlato con chi e quando (stiamo proteggendo solo il “cosa”). Accettare anche che la ricerca non funzionerà per questo contenuto.

Esperienza utente proposta

Jane accede alla sua pagina utente e clicca sul pulsante “attiva messaggistica crittografata”. Una volta cliccato, le verrà chiesto di inserire un segreto; l’interfaccia spiegherà chiaramente che, se dimentica questo segreto, non avrà MAI più accesso ai suoi messaggi crittografati.

Una volta attivata la messaggistica crittografata, apparirà un nuovo [ ] nell’interfaccia di creazione del messaggio con il testo [ ] crittografa messaggio. Questo sarà cliccabile solo se tutti i destinatari hanno l’opzione “attiva messaggistica crittografata” abilitata. Se alcuni non hanno chiavi pubbliche, al tentativo di cliccare apparirà il messaggio: “Spiacente, ma alcuni partecipanti non hanno la messaggistica crittografata abilitata”.

Jane decide di voler parlare in privato con Pete; lo aggiunge all’elenco dei partecipanti, clicca su crittografa messaggio e invia un messaggio a Pete.

Pete riceve una notifica che indica che Jane gli ha inviato un messaggio crittografato. Non c’è un titolo, solo l’informazione che esiste un messaggio crittografato e i link al messaggio (sia nelle notifiche via email che in quelle web).

Se Pete è sul dispositivo originale su cui ha abilitato la messaggistica crittografata, la sua passphrase segreta è già stata inserita e le credenziali sono già salvate in IndexedDB. Se Pete è su un nuovo dispositivo, gli verrà chiesto di inserire la sua passphrase segreta per attivare la messaggistica crittografata.

L’interfaccia mostrerà chiaramente un overlay o un hint visivo per indicare che il messaggio è crittografato.

Una volta avviata la comunicazione tra Jane e Pete, uno dei due può invitare nuove persone al messaggio, purché abbiano chiavi pubbliche.

Pete o Jane possono modificare la passphrase segreta quando vogliono; in tal caso, la chiave privata verrà ricrittografata con la nuova passphrase e inviata al server. (Per la V1 non sarà consentito modificare la chiave privata vera e propria, ma solo la passphrase).

Dettagli tecnici

In nessun momento verranno inviate al server conversazioni private non crittografate o credenziali private. L’unica fiducia riposta nel server sarà che nessuno abbia manipolato il payload JavaScript inviato al client.

Le coppie di chiavi pubbliche e private verranno generate al 100% lato client; successivamente, la chiave privata verrà crittografata utilizzando la crittografia simmetrica AES prima di essere consegnata al server per la conservazione. La passphrase verrà allungata utilizzando un sale generato casualmente e memorizzato sul server. L’allungamento della chiave avverrà lato client utilizzando PBKDF2 (disponibile nell’API Web Crypto). La coppia di chiavi privata/pubblica verrà memorizzata lato client in IndexedDB utilizzando un oggetto CryptoKey non esportabile. I dati di CryptoKey esportabili verranno rimossi dalla memoria il prima possibile.

La chiave privata crittografata e la chiave pubblica verranno memorizzate in campi personalizzati dell’utente. Solo current_user potrà leggere/scrivere la chiave privata crittografata; tutti gli utenti loggati potranno leggere le chiavi pubbliche di tutti gli utenti.

Le chiavi di conversazione verranno generate lato client all’avvio della conversazione o durante un invito e crittografate utilizzando tutte le chiavi pubbliche coinvolte nella conversazione. Questi dati verranno memorizzati in una tabella dedicata (user_id, topic_id, encrypted_conversation_key); questa riga potrà essere creata da qualsiasi utente nella conversazione, ma sarà leggibile solo da current_user == user_id.

Sarà prestata particolare cura per non esporre mai dati non crittografati al server, incluso assicurarsi che le bozze non vengano salvate in chiaro.

Per evitare una vasta categoria di errori, verranno utilizzati nuovi elementi DOM (con nuovi ID) per la modifica e l’anteprima del compositore. L’attuale .d-editor-input conterrà solo blob crittografati e l’anteprima tradizionale verrà disabilitata (ciò significa che saranno in gioco due aree di testo: una crittografata e una non crittografata). La crittografia verrà fortemente debouncata per evitare problemi di prestazioni.

Per la V1 (e per l’ambito di questo lavoro), siamo disposti a eliminare determinate funzionalità, tra cui il supporto per il caricamento di file, la visualizzazione dei link (oneboxing) per i contenuti crittografati e altri casi limite complessi.

Siamo d’accordo nel decrittare, elaborare e passare l’HTML attraverso un whitelister in tempo reale durante il rendering di questo contenuto privato.

Requisiti di documentazione

Prima dell’implementazione, verrà creata una specifica molto dettagliata, inclusi mockup web e, soprattutto, una panoramica dettagliata della sicurezza.

Requisiti di test

Questo plugin deve includere un set completo di test unitari e di integrazione sia lato client che lato server. Se accettate questo progetto, scrivete i test fin dall’inizio; non aspettate la fine del progetto per integrarli.

Preoccupazioni

Molte delle preoccupazioni sollevate in: https://www.nccgroup.trust/us/about-us/newsroom-and-events/blog/2011/august/javascript-cryptography-considered-harmful/ non sono più rilevanti grazie all’API Web Crypto (generazione di byte casuali veri, archiviazione delle chiavi private e così via). L’unico vettore principale che esiste è il server che invia al client JavaScript dannoso. Nel breve termine, gli utenti saranno semplicemente tenuti a fidarsi del server, come fanno con 1Password, LastPass e altre interfacce di sicurezza web. Nel lungo termine (v3/v4 - l’anno prossimo o dopo), potremmo considerare la distribuzione di un’estensione per browser che mostra un lucchetto sui siti in cui tutti gli hash di stabilità dei payload JS sono ben noti.

L’API WebCrypto è ancora relativamente giovane, ma ampiamente supportata; il plugin dovrebbe funzionare su tutti i browser da noi supportati.

Mockup semplici e approssimativi

* all’avvio di un messaggio, l’utente può scegliere di crittografare la conversazione; verrà visualizzato un avviso se uno dei partecipanti non ha chiavi pubbliche.

* gli utenti possono attivare la messaggistica crittografata cliccando quel pulsante e seguendo un’interfaccia che genera la coppia di chiavi.

Se la messaggistica crittografata è abilitata, dovrebbe semplicemente visualizzare “Hai la messaggistica crittografata abilitata”.

* Un’icona o un overlay di qualche tipo indicherà che un messaggio è crittografato.

Budget

Si tratta di un progetto molto complesso da realizzare, che richiede un’integrazione profonda e un’attenta revisione. Ci aspettiamo che sia estremamente ben testato (utilizzando sia test lato client che lato server). Il nostro budget attuale per un MVP è di 10.000 USD.

34 Mi Piace

If the implementation is open source with the rest of discourse I could probably get our lot to throw in £1000 or thereabouts to your budget.

12 Mi Piace

Cool, yes, this will be open source under the MIT license, with an additional full license assignment to Discourse.

Regarding browser support, we want to make sure it works on every platform: Chrome + Safari is a minimum (so it works on iPhone / Android / Desktop), but my preference is that we hit Firefox as well. Edge is in the nice-to-have and IE11 is in the I don’t really care department, especially if it is missing crypto stuff.

7 Mi Piace

I’ll get the ball rolling now then, couple of questions though.

  • Is it plausible for this project to accommodate group encrypted chat, even if up to a point?
  • Would “Force every PM encrypted” option be on the cards?

Not for the initial version. Maybe for version 2 or 3, a PM between 20 users should absolutely work for V1.

Yes this is fine as an option. Basically would disallow PM to users that don’t have encryption enabled (but still allow admins to PM them unconditionally). We would need to think this through, but I don’t want to add this to the scope of the spec quite yet.

4 Mi Piace

Thanks i’m obligated to sample an arbitrarily acceptable number of our PMs and reading people’s intimate conversations if only skimming is not only something I don’t want to do it takes time I haven’t got.

a PM between 20 users should absolutely work for V1.

That’s group chat in my context (Forgot where I am :slight_smile: ) and will be fine. I’d expect strong support from our lot.

Keep in mind with this plugin it is technically impossible for you to read members private conversations provided they have a reasonably strong passphrase.

They are encrypted in the database and only decrypted client side. You would have to add a code exploit to your server for you to be able to swing reading encrypted PMs. Longer term (in v3 / v4) this code exploit would result in a giant red flag on the screen for people who install the “confirm my encrypted discourse conversations have not been exploited” browser plugin.

1 Mi Piace

Yes that’s ideal, i’m obligated to look at them because I can look at them.

1 Mi Piace

This is fascinating. It would be refreshing to do something really technically challenging. But, at least for me, the cost / benefit of taking the time to master (assuming, optimistically, that I could) all the relevant pieces doesn’t make sense right now.

That said, I just did a little reading on cryptography and have a few questions / thoughts:

  • Am I correct in understanding that you would need to generate a new conversation key every time you added or removed a member from the PM?

  • You would need some protection or warning against using other plugins as well. I can imagine a scenario in which you install this plugin, then someone writes another plugin that exposes or stores the entered text in some way before it is encrypted.

  • Wouldn’t you need to also only allow this feature on sites that force https? From the article you linked.

    You can’t simply send a single Javascript file over SSL/TLS. You have to send all the page content over SSL/TLS. Otherwise, attackers will hijack the crypto code using the least-secure connection that builds the page.

    Otherwise, in addition to the issue of the server sending malicious javascript you could also have the issue of ‘hijacking’.

  • Searchable semantic encryption is possible (by no means do I mean to imply that I understand the description in that paper). I assume you’re excluding it as the cost / benefit isn’t worth it, at least for the MVP.

  • Why not use the Signal Protocol? (javascript library).

ps. for whoever takes this on

15 Mi Piace

Great questions:

The encrypted conversation key does not need to change on add. All members of the conversation have a copy of the decrypted conversation key. So to add a member you would encrypt this conversation key using the “invitee” public key and teach the server about that.

Technically it would be correct to amend the conversation key if you are removing members from a conversation, but we can wait on v2 for that. Cause it would be a very expensive operation from the client side, entire conversation would have to be re-encrypted, or complex multi conversation key systems need to be built.

Yes, the long term V3 / V4 goal here is to have a whitelist of JS integrity hashes stored in a browser extension. That is really the only way a client can know 100% that the “server is not messing with stuff”. However for V1 we trust the server and server operator not to be malicious.

Yes, if SSL is off all bets are off. We do not expect this feature to even remotely work if SSL is off.

Yes search is off the cards for now cause it is just going to be too hard to get right for the MVP.

Maybe, not against leaning on existing standards, but I suspect the Discourse integration work here is going to be enormous regardless.

11 Mi Piace

Congrats! @dan will be taking this project! We will update here as we make progress!

29 Mi Piace

Signed up to comment on this because I’m curious on the implementation as a developer myself.

I’m personally no cryptography pro, so forgive me if these are silly questions.

Would it not be viable to encrypt the message on the server-side using the public keys of people currently in the conversation, in this case?
Essentially I guess this would lead to a double layer of encryption - the data is encrypted client-side for true E2E encryption as described with the conversation key, and then encrypted on the way out by the server to only the public keys active in the conversation. At that point, removing a member from the conversation would mean any future messages wouldn’t be decryptable by them.

I’m not too sure on the security implications of nested encryption like that, however.

My second question is how well this would work cross-device? Does it require a private key on the device, or is that handled by the passphrase encrypted private key being stored?

4 Mi Piace

Interesting idea the “double” encrypting. It does though add more responsibility to the server and a lot of this is about removing responsibility from the server so I am not sure it is a great idea protocol wise.

Cross device is handled by retrieving the encrypted private key from the server and decrypting using the key phrase.

Longer term we can introduce more “security” modes with a super strict one when say the server never even stores the private key encrypted (like say 1 password), but short term this is out of scope.

10 Mi Piace

Welcome! :discourse: :heart:

Those are not silly questions at all! If you want to dig deeper, I highly recommend Dan Boneh’s courses on Coursera.org.

This depends a lot on the particularities of the system you use. Check out double DES (i.e. vulnerable to meet-in-the-middle) and triple DES.

Let’s say Eve used to be a part of a group discussion with Alice and Bob. Even if Alice or Bob kick Eve out she will still have the conversation key and theoretically, she could intercept the messages before they get to the server and decrypt them.

If the conversation key gets compromised, the safest approach is to revoke it and use a new one for new messages. Ideally, you’d probably want to re-encrypt the old messages.

7 Mi Piace

That makes sense to me, thanks for the explanation! (@sam too)

So adding or removing users from the conversation would involve decrypting everything client-side, revoking the conversation key and generating a new one, then re-encrypting messages before sending to the server?
Plus encrypting the new conversation key with the user passphrase and storing it.

1 Mi Piace

I’ve been talking to my wife about this feature. While this may raise an eyebrow at mealtime conversation in our family, she’s a security engineer for Thales eSecurity.

She’s of the opinion that the Specification needs some use cases with bad actors and how the system should respond. For example: Malicious Admin, Malicious SysOps.

This would then give rise to a security statement that could be presented to users of the system.

9 Mi Piace

I would love it if your wife or anyone interested in this problem at her work would pop by and give feedback.

@dan has made tremendous progress here, I am testing v1 with him this week.

To answer your specific question of bad sys admins. Overall if you can commandeer the web site and deliver malicious payloads our current v1 can not offer privacy. This is by design.

Our plans for v3/v4 is to have a browser plugin that validates every single JavaScript file on the page matches a particular hash in the whitelist. That way if you would be running this plugin you would be able to disallow unrecognized JS payloads.

Overall the underlying design means that passwords can not be fished out after the fact even if the server is malicious, but it can trick the client if it wishes to decrypt arbitrary payloads. Native browser plugins or a more refined web standard longer term will help eliminate this

14 Mi Piace

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.