Gostaríamos de encomendar um plugin que permita mensagens privadas e criptografadas entre usuários finais.
Este plugin já existe e é oficialmente suportado. Veja em Discourse Encrypt (deprecated)
Atualmente, há muito poucos ambientes online para comunicação segura, privada e de longo prazo. As ferramentas existentes geralmente são bastante complexas e exigem habilidades técnicas extremas para uso. Como resultado, a maioria da comunicação “privada” é feita de forma “curta” no Telegram, Skype ou WhatsApp. Além disso, esse modo de comunicação em massa não é adequadamente auditável, pois se baseia em ferramentas de código fechado e frequentemente em protocolos também fechados.
Gostaríamos de construir uma solução altamente utilizável e auditável para mensagens criptografadas em um plugin dedicado do Discourse.
Para isso, gostaríamos de nos basear em alguns princípios:
-
Construir a solução sobre a Web Crypto API.
-
Fazer com que o servidor armazene uma chave privada criptografada e uma chave pública por usuário.
-
Fazer com que o servidor armazene uma chave de conversa criptografada por participante em mensagens privadas (criptografada usando a chave privada do usuário final).
-
Armazenar todo o conteúdo em Markdown e os títulos na forma crua e criptografada por mensagem (criptografada usando a chave da conversa).
-
Aceitar a limitação de que o servidor sabe quem conversou com quem e quando (estamos protegendo apenas o “o quê”). Aceitar também que a busca não funcionará para esse conteúdo.
Experiência proposta para o usuário final
Jane acessa sua página de usuário e clica no botão “habilitar mensagens criptografadas”. Ao clicar, ela é solicitada a inserir uma senha secreta. A interface explica claramente que, se ela esquecer essa senha, NUNCA mais terá acesso às suas mensagens criptografadas.
Uma vez que as mensagens criptografadas estiverem habilitadas, um novo [ ] aparecerá na interface de criação de mensagens com o texto [ ] criptografar mensagem. Isso só será clicável se todos os destinatários tiverem a opção “habilitar mensagens criptografadas” ativada. Se alguns não tiverem chaves públicas, ao tentar clicar, será exibida a mensagem: “Desculpe, mas alguns dos participantes não têm mensagens criptografadas habilitadas”.
Jane decide conversar privadamente com Pete. Ela o adiciona à lista de participantes, clica em criptografar mensagem e envia uma mensagem para ele.
Pete recebe uma notificação informando que Jane enviou uma mensagem criptografada. Não há título, apenas a informação de que existe uma mensagem criptografada, com links para a mensagem (tanto na notificação por e-mail quanto na web).
Se Pete estiver no mesmo dispositivo onde habilitou as mensagens criptografadas, sua senha secreta já foi inserida e as credenciais já estão armazenadas no IndexedDB. Se ele estiver em um novo dispositivo, será solicitado que ele insira sua senha secreta para ativar as mensagens criptografadas.
A interface exibirá claramente uma sobreposição ou indicador visual para mostrar que a mensagem está criptografada.
Uma vez iniciada a comunicação entre Jane e Pete, qualquer um deles pode convidar novas pessoas para a conversa, desde que possuam chaves públicas.
Pete ou Jane podem alterar a senha secreta sempre que desejarem. Se fizerem isso, a chave privada será recriptografada usando a nova senha e enviada ao servidor. (Para a versão 1, não serão permitidas alterações na chave privada em si, apenas na senha.)
Detalhes técnicos
Em nenhum momento qualquer conversa privada não criptografada ou credenciais privadas serão enviadas ao servidor. A única confiança depositada no servidor será de que ninguém manipulou o payload JavaScript enviado ao cliente.
Os pares de chaves pública e privada serão gerados 100% no lado do cliente. Em seguida, a chave privada será criptografada usando criptografia simétrica AES antes de ser entregue ao servidor para guarda segura. A senha será estendida usando um sal gerado aleatoriamente e armazenado no servidor. O estiramento da senha será feito no cliente usando PBKDF2 (disponível na Web Crypto API). O par de chaves privada/pública será armazenado no cliente no IndexedDB usando um objeto CryptoKey não exportável. Dados de CryptoKey exportáveis serão removidos da memória o mais rápido possível.
A chave privada criptografada e a chave pública serão armazenadas em campos personalizados do usuário. Apenas o current_user poderá ler/gravar a chave privada criptografada; todos os usuários logados poderão ler as chaves públicas de todos os usuários.
As chaves de conversa serão geradas no lado do cliente no início da conversa ou ao convidar alguém, e serão criptografadas usando todas as chaves públicas envolvidas na conversa. Esses dados serão armazenados em uma tabela dedicada (user_id, topic_id, encrypted_conversation_key). Essa linha poderá ser criada por qualquer usuário da conversa, mas somente será legível quando current_user == user_id.
Será tomado cuidado especial para nunca vazar dados não criptografados para o servidor, incluindo garantir que rascunhos não sejam armazenados sem criptografia.
Para evitar uma grande classe de erros, novos elementos DOM (com novos IDs) serão usados para a edição e visualização do editor. A atual .d-editor-input conterá apenas blobs criptografados, e a visualização tradicional será desabilitada (ou seja, haverá duas áreas de texto: uma criptografada e outra não). A criptografia será fortemente desacoplada (debounced) para evitar problemas de desempenho.
Para a versão 1 (e o escopo deste item de trabalho), estamos dispostos a eliminar certas funcionalidades, incluindo suporte a uploads, oneboxing de conteúdo criptografado e outros casos complexos de borda.
Não temos problema em descriptografar, compilar e passar o HTML por um validador (whitelister) em tempo real ao renderizar esse conteúdo privado.
Requisitos de documentação
Antes da implementação, será criada uma especificação muito detalhada, incluindo mockups web e, mais importante, uma visão geral de segurança detalhada.
Requisitos de teste
Este plugin deve incluir um conjunto abrangente de testes unitários e de integração, tanto no lado do cliente quanto no servidor. Se você aceitar este projeto, escreva os testes desde o início; não espere até o fim do projeto para adicioná-los posteriormente.
Preocupações
Muitas das preocupações mencionadas em: https://www.nccgroup.trust/us/about-us/newsroom-and-events/blog/2011/august/javascript-cryptography-considered-harmful/ não são mais relevantes devido à Web Crypto API (geração de bytes aleatórios verdadeiros, armazenamento de chaves privadas e muito mais). O único vetor principal existente é o servidor enviar JavaScript malicioso ao cliente. A curto prazo, os usuários simplesmente precisarão confiar no servidor da mesma forma que confiam no 1Password, LastPass e outras interfaces de segurança web. A longo prazo (versão 3/4 – no próximo ano ou depois), podemos considerar o lançamento de uma extensão de navegador que exibe um cadeado em sites onde todos os hashes de estabilidade dos payloads JavaScript são bem conhecidos.
A WebCrypto API ainda é relativamente nova, mas amplamente suportada. O plugin deve funcionar em todos os navegadores que suportamos.
Mockups simples e rascunhos
* Ao iniciar uma mensagem, o usuário pode optar por criptografar a conversa. Um aviso será exibido se algum dos participantes estiver sem chaves públicas.
* Os usuários podem habilitar mensagens criptografadas clicando nesse botão e seguindo uma interface que gera o par de chaves.
Se as mensagens criptografadas estiverem habilitadas, deve ser exibido simplesmente: “Você tem mensagens criptografadas habilitadas”.
* Um ícone ou sobreposição indicará que uma mensagem está criptografada.
Orçamento
Este é um projeto muito complexo de implementar, que exige integração profunda e revisão cuidadosa. Esperamos que seja extremamente bem testado (usando testes tanto no lado do cliente quanto no servidor). Nosso orçamento atual para um MVP é de 10 mil dólares americanos (USD).


