Eu sou um grande fã de WebSockets e socket.io, e hoje vou falar de comunicações.
Imagine que temos um servidor WebSocket e conectamos nossa aplicação a esse servidor (mesmo usando https/WSS). Se abrirmos o console do nosso navegador, podemos inspecionar as nossas comunicações WebSocket. Nós também podemos ativar a depuração. Isso funciona de forma semelhante quando iniciamos o modo promiscuous dentro de nossa interface de rede. Veremos todos os pacotes. Não apenas os pacotes que o servidor está enviando para nós.
Se enviarmos informações confidenciais por websockets, isso significa que um usuário logado pode ver a informação de outros. Podemos separar namespaces no nosso servidor socket.io. Nós também podemos fazer outra coisa: criptografar as comunicações usando cripto-js.
Eu criei um pequeno wrapper para usá-lo com socket.io.
Podemos instalar nossa dependência de servidor.
npm g-crypt
E instalar a nossa dependência do cliente com bower.
bower install g-crypt
E usar dentro do nosso servidor.
var io = require('socket.io')(3000), Crypt = require("g-crypt"), passphrase = 'super-secret-passphrase', crypter = Crypt(passphrase); io.on('connection', function (socket) { socket.on('counter', function (data) { var decriptedData = crypter.decrypt(data); setTimeout(function () { console.log("counter status: " + decriptedData.id); decriptedData.id++; socket.emit('counter', crypter.encrypt(decriptedData)); }, 1000); }); });
E agora uma simples aplicação HTTP.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> Open console to see the messages <script src="http://localhost:3000/socket.io/socket.io.js"></script> <script src="assets/cryptojslib/rollups/aes.js"></script> <script src="assets/g-crypt/src/Crypt.js"></script> <script> var socket = io('http://localhost:3000/'), passphrase = 'super-secret-passphrase', crypter = Crypt(passphrase), id = 0; socket.on('connect', function () { console.log("connected! Let's start the counter with: " + id); socket.emit('counter', crypter.encrypt({id: id})); }); socket.on('counter', function (data) { var decriptedData = crypter.decrypt(data); console.log("counter status: " + decriptedData.id); socket.emit('counter', crypter.encrypt({id: decriptedData.id})); }); </script> </body> </html>
Agora nossa comunicação está criptografada e usuários logados não podem ler os dados de outros usuários.
A biblioteca é um simples wraper.
Crypt = function (passphrase) { "use strict"; var pass = passphrase; var CryptoJSAesJson = { parse: function (jsonStr) { var j = JSON.parse(jsonStr); var cipherParams = CryptoJS.lib.CipherParams.create({ciphertext: CryptoJS.enc.Base64.parse(j.ct)}); if (j.iv) cipherParams.iv = CryptoJS.enc.Hex.parse(j.iv); if (j.s) cipherParams.salt = CryptoJS.enc.Hex.parse(j.s); return cipherParams; }, stringify: function (cipherParams) { var j = {ct: cipherParams.ciphertext.toString(CryptoJS.enc.Base64)}; if (cipherParams.iv) j.iv = cipherParams.iv.toString(); if (cipherParams.salt) j.s = cipherParams.salt.toString(); return JSON.stringify(j); } }; return { decrypt: function (data) { return JSON.parse(CryptoJS.AES.decrypt(data, pass, {format: CryptoJSAesJson}).toString(CryptoJS.enc.Utf8)); }, encrypt: function (data) { return CryptoJS.AES.encrypt(JSON.stringify(data), pass, {format: CryptoJSAesJson}).toString(); } }; }; if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') { CryptoJS = require("crypto-js"); module.exports = Crypt; } else { window.Crypt = Crypt; }
A biblioteca está disponível no meu GitHub, e também podemos utilizá-la com npm e bower.
***
Gonzalo Ayuso faz parte do time de colunistas internacionais do iMasters. A tradução do artigo é feita pela redação iMasters, com autorização do autor, e você pode acompanhar o artigo em inglês no link: https://gonzalo123.com/2016/09/26/encrypt-websocket-socket-io-communications/