websocket是一种在单个TCP连接上进行全双工通信的协议,被广泛用于构建实时应用的程序当中。为保证数据传输的安全和完整,通常会对websocket的消息进行加密传输。下面就来华纳云同大家一起分析关于websocket消息加密的方式和步骤。
第一种,通过TLS实现websocket的加密连接。通过 WebSocket Secure(wss://)协议启用 TLS 加密,从而在传输层对所有 WebSocket 通信进行加密。这样的方式简单易用,标准化的加密传输方式,可以保证数据在传输中的安全性。通常需要有效的 SSL/TLS 证书,让WebSocket 服务器支持 TLS。在客户端使用 wss:// 协议连接 WebSocket 服务器:
// JavaScript 客户端示例
const ws = new WebSocket('wss://example.com/socket');
此外,还可以在应用层对消息内容进行加密,这样来增强安全性和防止中间人攻击。常用类型有:对称加密、非对称加密、混合加密、消息认证。
对称加密是使用相同的密钥进行的加密和解密,适用于传输双方都可以安全共享密钥的场景,常用的算法有AES、DES、3DES。实现流程是先在客户端和服务器端之间共享一个密钥,通过安全的密钥交换协议(如 Diffie-Hellman)实现。使用对称加密算法加密消息,通过WebSocket 发送加密的消息。接收方使用相同的密钥解密信息。
// JavaScript 客户端示例
const crypto = require('crypto');
// 加密函数
function encrypt(text, key) {
const iv = crypto.randomBytes(16);
const cipher = crypto.createCipheriv('aes-256-cbc', Buffer.from(key), iv);
let encrypted = cipher.update(text);
encrypted = Buffer.concat([encrypted, cipher.final()]);
return iv.toString('hex') + ':' + encrypted.toString('hex');
}
// 解密函数
function decrypt(text, key) {
const textParts = text.split(':');
const iv = Buffer.from(textParts.shift(), 'hex');
const encryptedText = Buffer.from(textParts.join(':'), 'hex');
const decipher = crypto.createDecipheriv('aes-256-cbc', Buffer.from(key), iv);
let decrypted = decipher.update(encryptedText);
decrypted = Buffer.concat([decrypted, decipher.final()]);
return decrypted.toString();
}
const key = crypto.randomBytes(32); // 生成密钥
const message = "Hello, WebSocket!";
const encryptedMessage = encrypt(message, key);
ws.send(encryptedMessage); // 发送加密消息
ws.onmessage = function(event) {
const decryptedMessage = decrypt(event.data, key);
console.log("解密后的消息: ", decryptedMessage);
};
而非对称加密,是使用公钥加密和私钥解密。这样的方式非常适合用于无需共享密钥的场景,但是对于性能的要求比较高。常用的算法是RSA、ECC。先在服务器生成公钥和私钥对,并将公钥分发给客户端,客户端使用服务器的公钥加密消息,通过WebSocket 发送加密的消息。服务器使用私钥解密消息。
// Node.js 服务器示例
const crypto = require('crypto');
// 生成密钥对
const { publicKey, privateKey } = crypto.generateKeyPairSync('rsa', {
modulusLength: 2048,
});
// 加密函数
function encrypt(text, publicKey) {
const buffer = Buffer.from(text, 'utf8');
const encrypted = crypto.publicEncrypt(publicKey, buffer);
return encrypted.toString('base64');
}
// 解密函数
function decrypt(encryptedText, privateKey) {
const buffer = Buffer.from(encryptedText, 'base64');
const decrypted = crypto.privateDecrypt(privateKey, buffer);
return decrypted.toString('utf8');
}
const message = "Hello, WebSocket!";
const encryptedMessage = encrypt(message, publicKey);
ws.send(encryptedMessage); // 发送加密消息
ws.onmessage = function(event) {
const decryptedMessage = decrypt(event.data, privateKey);
console.log("解密后的消息: ", decryptedMessage);
};
混合加密是结合对称和非对称,利用非对称加密交换对称密钥,进一步提高安全性和效率。先使用非对称加密算法安全的交换对称加密密钥。使用交换的对称密钥对消息进行加密。通过WebSocket 发送加密的消息。使用对称密钥解密接受到的消息。
还有一种消息认证,加密可以保护消息的机密性,但还是存在消息被修改的风险。所以经过消息认证机制提高消息防止修改的安全性。如哈希消息认证码,是通过一个共享的密钥和哈希算法HMAC来验证消息的完整和身份。发送使用共享密钥和消息生成HMAC,通过WebSocket 发送加密的消息和 HMAC。接收方使用相同的密钥验证HMAC以确保消息未被修改。
const crypto = require('crypto');
function createHmac(message, key) {
return crypto.createHmac('sha256', key).update(message).digest('hex');
}
const hmacKey = crypto.randomBytes(32); // HMAC密钥
const message = "Hello, WebSocket!";
const encryptedMessage = encrypt(message, key); // 使用对称加密加密消息
const hmac = createHmac(encryptedMessage, hmacKey); // 创建 HMAC
ws.send(JSON.stringify({ data: encryptedMessage, hmac })); // 发送加密消息和 HMAC
ws.onmessage = function(event) {
const { data, hmac: receivedHmac } = JSON.parse(event.data);
const expectedHmac = createHmac(data, hmacKey);
if (receivedHmac === expectedHmac) {
const decryptedMessage = decrypt(data, key);
console.log("解密后的消息: ", decryptedMessage);
} else {
console.error("消息被修改");
}
};
如何在 Node.js 环境中使用 WebSocket 实现加密传输:如服务端代码(Node.js)
const WebSocket = require('ws');
const crypto = require('crypto');
const server = new WebSocket.Server({ port: 8080 });
const { publicKey, privateKey } = crypto.generateKeyPairSync('rsa', {
modulusLength: 2048,
});
server.on('connection', (ws) => {
ws.on('message', (message) => {
const buffer = Buffer.from(message, 'base64');
const decrypted = crypto.privateDecrypt(privateKey, buffer);
console.log('接收到的消息:', decrypted.toString());
});
const welcomeMessage = '欢迎连接 WebSocket!';
const encryptedMessage = crypto.publicEncrypt(publicKey, Buffer.from(welcomeMessage));
ws.send(encryptedMessage.toString('base64'));
});
console.log('WebSocket 服务器运行在 ws://localhost:8080');
客户端代码:
const WebSocket = require('ws');
const crypto = require('crypto');
const ws = new WebSocket('ws://localhost:8080');
const { publicKey, privateKey } = crypto.generateKeyPairSync('rsa', {
modulusLength: 2048,
});
ws.on('open', () => {
const message = 'Hello, WebSocket!';
const encryptedMessage = crypto.publicEncrypt(publicKey, Buffer.from(message));
ws.send(encryptedMessage.toString('base64'));
});
ws.on('message', (message) => {
const buffer = Buffer.from(message, 'base64');
const decrypted = crypto.privateDecrypt(privateKey