Cryptage de bout en bout entre clients, avec un serveur au milieu

Messagerie privée instantanée vraiment privée

a marqué ce sujet comme résolu.

Hello tout le monde !

Je développe depuis quelque temps un site (de rencontre, pour faire simple) dans lequel je mets l'accent sur la sécurité et l'anonymat.

Je m'en sors pour la plupart des sujets, mais je bloque pas mal sur la messagerie privée, que j'aimerais rendre indéchiffrable par le serveur seul (en gros éviter qu'en cas d'extraction de la BDD, les MP ne se retrouvent au grand air).

J'ai bien eu quelques idées, mais il y a toujours une des contraintes suivantes qui bloque :

  • Messages entre 2 utilisateurs (stockés dans une base MySQL)
  • Chaque utilisateur peut être connecté sur plusieurs appareils/navigateurs en même temps
  • Rien à installer ou configurer côté utilisateur : tout doit être transparent et simple
  • Techno push autant que possible (pour l'instant via Socket.IO et un back Node), mais utilisation à l'ancienne (via un formulaire) dispo en cas de problème
  • Compatible sans imposer le JS à l'utilisateur de préférence

C'est d'ailleurs ce dernier point qui bloque souvent : je suis bien conscient que ça touche une part minime des utilisateurs, mais si ça peut fonctionner partout ce serait un plus (je reste cependant ouvert aux propositions ne prenant en compte cette contrainte).


Une idée que j'ai serait d'utiliser des variables de session (donc périssables) pour crypter/décrypter, mais cela ne fonctionnerait que pour de l'instantané et compliquerait le travail pour consulter les anciens messages.

Pour l'instant je fonctionne de la façon suivante, sans cryptage réel (sauf celui que le serveur peut déchiffrer seul, donc sans bonne sécurité) :

  • Un serveur PHP (avec CodeIgniter comme framework) stocke les infos dans une base MySQL et permet d'afficher les derniers messages et d'en envoyer à l'ancienne via un formulaire classique
  • Un JS client se connecte à un serveur Node via Socket.io puis lui envoie les cookies du client
  • Le serveur Node envoie une requête au serveur PHP (via une API interne) avec ces cookies pour récupérer les infos de l'utilisateur
  • Le serveur Node confirme à l'utilisateur qu'il est connecté et lui permet d'envoyer des messages
  • Quand l'utilisateur envoie un message via la socket, Node stocke le message dans la base MySQL et notifie les sockets actives concernées (celles de l'utilisateur courant et celles du destinataire)
  • Quand l'utilisateur reçoit un message, le JS client l'affiche à la suite des autres

Le but étant que la majorité du site soit sur une architecture PHP, sachant que tout ce qui demande du temps réel ou des choses plus spécialisées peuvent être faite avec Node (ou potentiellement avec autre chose, mais je préfère m'en tenir à des choses que je connais).

Le problème de localStorage c'est que ça va être difficiles pour ceux qui utilisent plusieurs appareils/navigateurs. L'upload de fichiers j'oublie : ça va être la merde sur mobile et surtout c'est loin d'être simple (le but étant que tout le monde profite de la même expérience sans configuration spécifique).

Pour les navigateurs un peu anciens c'est pas trop grave, je comptais déjà pas être compatible avec IE8 et inférieurs, ça restreint un peu plus la cible mais c'est pas bien grave (surtout avec les MAJ automatiques qui sont présentes presque partout).

Du coup je pense que je stockerai la version cryptée en base (avec d'éventuelles infos annexes nécessaire au décryptage mais qui ne le permettent pas à elles seules) et j'afficherai un message par défaut le temps que le JS affiche les messages décryptés (qui seront sûrement chargés en Ajax ou via les WebSockets pour le coup).

T'as des contraintes assez poussés ^^.

Sinon, tu pourrais utiliser un algo comme PGP mais qui utilise un clé privée qui serait de taille d'un mot de passe. Comme ça l'utilisateur peut la choisir et elle est enregistrée nulle part. L’inconvénient c'est que l'algorithme ne sera jamais autant sécurisé que PGP.

Effectivement, ça peut être une solution (moins sécurisée c'est clair, mais bon)…

Et comme je ne demande pas de mot de passe pour le compte, aucun risque de doublon de ce côté-là et ça ferait un seul mot de passe à retenir.

Faut voir niveau sécurité si ça devient critique ou non (en s'assurant aussi que les clés soient un minimum bien foutues).

Le problème c'est le fait que tu veuille donné la possibilité de plusieurs terminaux… hors soit la clé et du coté du client et c'est de sa responsabilité et en soie c'est déjà un problème, imagine son disque dur crash, ou bêtement un reset du navigateur et hop, l'utilisateur n'a plus accès à rien sur le site (enfin, sa à la limite, à toi de voir ^^ ). Soit le clé est du coté serveur et du coup en s'authentifiant l'utilisateur la récupère sur tous les terminaux désiré, sauf qu'évidement dans ce cas là sa sert à rien de masquer le contenu sur le serveur vu que t'as les clé qui va avec ^^

Éventuellement ce qui pourrai se faire c'est comme pour OAuth, un service dédié pour le clé, donc le serveur applicatif qui stocke les message chiffré et un autre serveur qui aurai les clés, lorsque l'on s'identifie avec un terminal on récupère sa clé sur le serveur d'authentification que l'on copie chez le client pour qu'il puisse chiffrer ses messages.

Dans ce cas, si la bdd de l'un ou l'autre serveur serait volée pas de problème…

+0 -0

Ça fait beaucoup de contraintes, je sais bien, malheureusement je peux pas empêcher les utilisateurs de se connecter depuis plusieurs terminaux.

Le système de double serveur me paraît pas mal, tant que c'est transparent pour l'utilisateur. Pour l'instant j'ai qu'un dédié mais je peux aussi utiliser un petit mutualisé basique pour faire des tests…

Oui, sa sera totalement transparent pour l'utilisateur.

L'idée c'est que lorsqu'il s'inscrit son compte est créer sur le serveur applicatif ainsi que sur le serveur des clé avec une clé générée aléatoirement.
Lorsqu'il se connecte sur le serveur applicatif on regarde dans les cookie s'il a déjà la clé de chiffrement (pour un chiffrement en js), si ce n'est pas le cas on génère un jeton pour qu'en ajax le client aille récupérer la clé de chiffrement (et d'un autre coté le serveur applicatif précise au serveur des clé que le jeton est valide). En ajax on récupère cette clé, de cette manière la clé n'est même pas passé par le serveur applicatif. Donc même s'il venait à être complètement piraté il ne verrai quand même pas les messages en clair.

Après si tu veux que le système puisse fonctionné sans javascript… le problème c'est que c'est plus chiffré de bout en bout… le serveur applicatif verra forcément les messages en clair vu que le client n'aura pas été capable de chiffré lui même le message.
Au niveau du principe sa reste le même sauf que plutôt que c'est le client qui aille demandé la clé c'est le serveur qui le fera pour lui.

A noté quand même qui faut réfléchir un minimum… soit chaque utilisateur à une paire de clé publique/privée (genre RSA), du coup quand il y a une conversation et que tu veux qu'a la fois le destinataire et l'émetteur puisse voir le message il faut le chiffré deux fois (avec la clé publique de chacun d'entre eux). Soit on créée une clé symétrique pour chaque message qu'on rend accessible à chaque participant.

+0 -0

Ok, je vois le principe, reste juste à mieux comprendre le principe de ton dernier paragraphe pour faire le bon choix.

Par contre j'ai un doute : si le client est capable d'aller chercher la clé, alors le serveur de messagerie en est théoriquement capable aussi, non ? Donc une attaque bien foutue peut récupérer l'ensemble BDD + clés et tout déchiffrer (bon là on est sur de la parano totale, surtout pour un site sans données sensibles — juste privées), non ?

Malheureusement oui… et même si sur le serveur de clé on donnait une directive du genre "Interdis d'envoyé les clé à l'ip du serveur applicatif" à partir du moment ou un pirate contrôlerai totalement le serveur applicatif il lui suffit de générer autant de jetons qu'il veut et qu'il aille récupérer lui même les clés depuis son ordinateur à lui.

En réfléchissant à la question, si un pirate venait à prendre le contrôle du serveur applicatif il pourrai effectivement récupérer toutes les données de toute façon. Le truc c'est qu'il faut déjà prendre le contrôle et conserver l'accès assez longtemps. Si je me mes à la place d'un pirate, je fais tout mon possible pour pénétrer le serveur, si j'entre le premier truc que je fais c'est chopé la bdd. Une fois fais je vais vérifier et me rendre compte que les messages sont chiffré. A partir de là je récupère les sources et je tente de comprendre.

Tous sa prend du temps, une fois que le pirate à compris là il peu développer une méthode pour récupérer les clés. Pendant tout ce temps, si tu es attentif à ton serveur tu peux tout verrouiller et donc empêcher l'accès aux messages.

+0 -0

Pour le deuxième bdd avec les clés étaient plutôt un serveur applicatif indépendant ?

C'est-à-dire impossibilité d'envoyer toute la BDD en une seule requête mais l'obligation de faire une requête pour une clé et de saisir une clé utilisateur ? En limitant chaque essai de quelques secondes secondes.

Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte