在React前端与后端通信时,如果直接发送登录密码、用户隐私等敏感字段,流量被抓包后就会完全暴露。采用RSA公钥加密AES密钥的交换思路,可以让对称加密的高性能和非对称加密的密钥安全分发同时成立。后端持有RSA私钥,只把公钥交给前端,前端本地生成AES密钥后用公钥加密上报,之后双方用AES加密业务数据,既防窃听也控制了计算开销。

为什么需要RSA与AES配合而不是单用其中一种
很多初学者会问,既然RSA能加密,为什么不直接用RSA加密所有请求数据。根本原因在于RSA属于非对称算法,其运算复杂度远高于AES这类对称算法,且单次加密的数据长度受密钥位数限制,例如2048位RSA最多加密约245字节(取决于填充方式)。当接口需要传输几KB的表单或文件元信息时,纯RSA方案既慢又容易出错。
AES的痛点则相反,它的加密解密极快,适合大块数据,但密钥本身必须在网络上分发。如果AES密钥明文传输,那么后续所有加密都形同虚设。把AES密钥用RSA公钥加密后传输,就相当于把钥匙装进只有后端私钥能开的保险箱,前端每次会话生成不同AES密钥,实现了前向安全。这种混合加密结构在HTTPS之外再做一层应用级保护时尤其有用,比如内网隔离环境或防抓包加固场景。
从架构视角看,RSA负责解决密钥信任问题,AES负责解决吞吐效率问题。后端可以在用户登录时下发公钥,前端在内存中生成crypto_key并加密回传,之后十分钟内的请求都带AES密文。即便攻击者拿到公钥,没有私钥也无法还原AES密钥,更解不开业务数据。
React前端如何生成AES密钥并用RSA加密
在React组件中,我们可以借助crypto-js生成随机AES密钥,再使用jsencrypt库加载后端公钥进行加密。下面的代码演示了核心流程:先准备公钥字符串,随机生成32字节密钥和IV,用CryptoJS的AES方法加密测试文本,再把密钥和IV拼接后用RSA加密。
import CryptoJS from 'crypto-js';
import JSEncrypt from 'jsencrypt';
// 后端下发的RSA公钥,实际项目中从接口获取
const publicKey = '-----BEGIN PUBLIC KEY-----nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A' +
'nMOCKKEYMOCKKEYMOCKKEYMOCKKEYMOCKKEYMOCKKEYMOCKKEYn-----END PUBLIC KEY-----';
// 生成随机AES密钥与IV
function generateAesMaterial() {
const key = CryptoJS.lib.WordArray.random(32);
const iv = CryptoJS.lib.WordArray.random(16);
return { key, iv };
}
// 用AES加密数据
function aesEncrypt(plainText, key, iv) {
const encrypted = CryptoJS.AES.encrypt(plainText, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
return encrypted.toString();
}
// 用RSA公钥加密AES材料
function rsaEncryptAesKey(keyHex, ivHex) {
const encryptor = new JSEncrypt();
encryptor.setPublicKey(publicKey);
const merged = keyHex + '|' + ivHex;
return encryptor.encrypt(merged);
}
const { key, iv } = generateAesMaterial();
const keyHex = key.toString();
const ivHex = iv.toString();
const aesCipher = aesEncrypt('用户敏感数据', key, iv);
const rsaCipher = rsaEncryptAesKey(keyHex, ivHex);
console.log('AES密文:', aesCipher);
console.log('RSA加密的密钥包:', rsaCipher);
上述代码中,WordArray.random保证密钥不可预测,CBC模式和Pkcs7填充是前后端对齐的常见选择。RSA加密前把key和iv用竖线拼接,后端私钥解密后再拆分,避免多次加密带来的对齐问题。
需要注意,jsencrypt默认使用PKCS1 v1.5填充,如果后端用Java的RSA/ECB/PKCS1Padding可以正常对接;若后端要求OAEP填充,则需要更换支持OAEP的库如node-forge。另外公钥字符串中的换行不能丢失,否则实例化会失败。前端不要把AES密钥持久化到localStorage,会话结束即销毁最安全。
后端校验与整体通信时序设计
后端在收到前端首次握手请求时,用私钥解密RSA密文得到AES密钥和IV,随后将该会话密钥绑定到用户token或临时会话ID。之后的业务接口前端都用AES加密body,后端用会话密钥解密。时序上可以分为三步:获取公钥、交换密钥、加密通信。
| 阶段 | 前端动作 | 后端动作 |
|---|---|---|
| 获取公钥 | 调用/api/pubkey拿到RSA公钥 | 返回缓存的RSA公钥字符串 |
| 密钥交换 | 生成AES材料,RSA加密后POST到/api/handshake | 私钥解密,存会话密钥,返回成功标识 |
| 业务传输 | 用AES加密请求体,带会话ID发送 | 按会话ID取密钥,AES解密并处理 |
这种设计的优势是每次前端刷新页面或重新登录都会换新AES密钥,即便某次会话密钥泄露,历史数据也不会被批量解密。为防止重放,后端可在握手时下发一次性nonce,前端把nonce拼进AES加密内容,后端校验通过才认数据。
在React里可以把握手逻辑封装到独立的securityClient模块,用Context把AES密钥提供给业务组件,避免到处写加密代码。同时要处理公钥接口失败、RSA解密异常等边界,比如网络降级时提示用户而不静默发明文。只要前后端填充模式、编码格式(如Base64或Hex)严格一致,这套RSA加AES密钥交换方案就能在React应用中稳定落地。
ReactRSAAES_key_exchange修改时间:2026-08-13 19:21:27