You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Socket.io JS程序中集成AES加密遇错,求解决方案与替代方案

Socket.io集成AES加密的错误修正与替代方案

一、现有代码的核心问题与修正方案

你的代码存在三个关键问题:密钥同步不统一、加解密参数不兼容、数据格式不匹配,以下是修正后的完整代码及说明:

修正后的客户端代码(client.html)

<!DOCTYPE html>
<html>
<head>
    <title>Socket.io Client</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>
    <script src="https://cdn.socket.io/socket.io-3.1.3.min.js"></script>
</head>
<body>
    <form>
        <label for="message">Message:</label>
        <input type="text" id="message" name="message"><br><br>
        <button type="button" onclick="sendMessage()">Send</button>
    </form>
    <script>
        const socket = io('http://localhost:8080');
        let encryptionKey; // 存储服务器下发的统一密钥

        // 接收服务器发送的密钥并转换格式
        socket.on('key', (data) => {
            encryptionKey = CryptoJS.lib.WordArray.create(data.key);
            console.log('已获取加密密钥');
        });

        function sendMessage() {
            if (!encryptionKey) {
                alert('请等待服务器下发加密密钥');
                return;
            }

            const message = document.getElementById('message').value;
            console.log(`原始消息: ${message}`);

            // 生成16字节随机IV(CBC模式必需)
            const iv = CryptoJS.lib.WordArray.random(16);
            // 用AES-256-CBC模式加密,与服务端参数统一
            const cipher = CryptoJS.AES.encrypt(message, encryptionKey, {
                iv: iv,
                mode: CryptoJS.mode.CBC,
                padding: CryptoJS.pad.Pkcs7
            });

            // 将IV和密文一起发送(解密必须用同一IV)
            socket.emit('encrypted-message', {
                ciphertext: cipher.ciphertext.toString(CryptoJS.enc.Base64),
                iv: iv.toString(CryptoJS.enc.Base64)
            });
            console.log(`加密消息已发送: ${cipher.toString()}`);
        }
    </script>
</body>
</html>

修正后的服务端代码(server.js)

const express = require('express');
const app = express();
const http = require('http');
const server = http.createServer(app);
const io = require('socket.io')(server);
const crypto = require('crypto');

app.get('/', (req, res) => {
  res.sendFile(__dirname + '/client.html');
});

io.on('connection', (socket) => {
  console.log('客户端已连接');

  // 生成32字节AES-256密钥,下发给客户端
  const key = crypto.randomBytes(32);
  socket.emit('key', { key });

  socket.on('encrypted-message', ({ ciphertext, iv }) => {
    console.log(`收到加密消息: ${ciphertext}`);

    try {
      // 转换为Node.js crypto兼容的Buffer格式
      const keyBuffer = key;
      const ivBuffer = Buffer.from(iv, 'base64');
      const ciphertextBuffer = Buffer.from(ciphertext, 'base64');

      // 创建解密器,与客户端加密参数完全匹配
      const decipher = crypto.createDecipheriv('aes-256-cbc', keyBuffer, ivBuffer);
      let decrypted = decipher.update(ciphertextBuffer);
      decrypted = Buffer.concat([decrypted, decipher.final()]);

      console.log(`解密消息: ${decrypted.toString('utf8')}`);
    } catch (err) {
      console.error('解密失败:', err);
    }
  });
});

server.listen(8080, () => {
  console.log('服务器运行在8080端口');
});

修正关键点说明

  1. 密钥统一:服务器生成密钥并下发给客户端,避免两端密钥不一致;
  2. 参数对齐:双方统一使用AES-256-CBC模式+Pkcs7填充,确保加解密逻辑兼容;
  3. IV传递:加密时生成的随机IV必须随密文一起发送,解密时使用同一IV;
  4. 格式转换:正确处理CryptoJS的WordArray与Node.js Buffer之间的格式转换。

二、AES加密的替代方案

1. 浏览器原生Web Crypto API

无需引入第三方库,浏览器原生支持,安全性和性能更优:
客户端核心代码示例:

let encryptionKey;

socket.on('key', async (data) => {
    // 将服务器下发的密钥转换为Web Crypto兼容格式
    encryptionKey = await crypto.subtle.importKey(
        'raw',
        data.key,
        { name: 'AES-CBC', length: 256 },
        false,
        ['encrypt']
    );
});

async function sendMessage() {
    if (!encryptionKey) {
        alert('请等待密钥下发');
        return;
    }
    const message = document.getElementById('message').value;
    const iv = crypto.getRandomValues(new Uint8Array(16));
    const encoder = new TextEncoder();
    const ciphertext = await crypto.subtle.encrypt(
        { name: 'AES-CBC', iv: iv },
        encryptionKey,
        encoder.encode(message)
    );

    // 转换为Base64发送给服务端
    socket.emit('encrypted-message', {
        ciphertext: btoa(String.fromCharCode(...new Uint8Array(ciphertext))),
        iv: btoa(String.fromCharCode(...iv))
    });
}

服务端仍使用Node.js crypto模块解密,逻辑与之前一致。

2. 使用Socket.io加密扩展库

用socket.io-encrypt简化加密流程,自动处理密钥交换和加解密:
安装依赖:

npm install socket.io-encrypt

服务端核心代码:

const io = require('socket.io')(server);
const encrypt = require('socket.io-encrypt');
// 使用动态生成的密钥初始化加密中间件
io.use(encrypt(crypto.randomBytes(32)));

// 后续发送/接收消息自动加解密
io.on('connection', (socket) => {
    socket.on('message', (data) => {
        console.log('自动解密后的消息:', data);
    });
});

客户端核心代码:

const socket = io('http://localhost:8080', {
    extraHeaders: { 'socket.io-encrypt': '服务器生成的密钥' }
});
// 发送消息自动加密
socket.emit('message', 'Hello World');

3. TLS+应用层加密双重保障

生产环境下先启用HTTPS/WSS(TLS加密)保障传输链路安全,再叠加应用层AES加密实现端到端加密,双重提升安全性。

内容的提问来源于stack exchange,提问作者Vishnu Nair

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 19:27:22