接口数据加解密解决方案文档 接口数据加解密解决方案文档目录方案概述核心架构设计前端实现详解后端实现详解密钥管理方案集成步骤示例代码附录方案概述设计目标本方案旨在为前后端交互的接口数据提供安全、高效、透明的加解密机制,确保敏感数据在传输过程中的安全性。核心特性双重加密算法支持:同时支持 AES-CBC 和 SM4-CBC 国密算法动态密钥选择:每次加密随机选择密钥和算法,提高破解难度多存储模式:支持本地缓存和 Redis 缓存两种密钥存储方式注解驱动:基于 Spring AOP + 注解,业务代码零侵入完整性校验:内置 MD5 指纹验证,防止数据篡改技术栈技术版本说明Spring Boot-基础框架Spring AOP-请求/响应切面处理Redis-密钥分布式缓存(可选)BouncyCastle-国密算法支持核心架构设计整体流程┌──────────┐ ┌──────────┐ ┌──────────┐ │ 前端 │ │ 网络 │ │ 后端 │ └────┬─────┘ └────┬─────┘ └────┬─────┘ │ │ │ │ 1. 请求数据加密 │ │ │ ───────────────────── │ │ │ 2. 请求体解密 │ │ │ ──────────────────── │ │ │ 3. 业务处理 │ │ 4. 响应体加密 │ │ ──────────────────── │ │ 5. 响应数据解密 │ │ │ │ │数据结构设计加密后的数据包含完整的元信息和加密内容,采用二进制编码后通过 Base64 传输:偏移长度字段名说明01first首字节校验位11algorithmIndex算法索引 (0:AES, 1:SM4)21privateKeyIndex私钥索引31ivKeyIndexIV向量索引41keyLength密钥池大小51keyGroupIndex密钥组索引64finger指纹104clientIp客户端IP1416md5ContentMD5完整性校验302reserved保留字段32Ndata实际加密数据响应体结构{"success":true,"message":"操作成功","data":"Base64编码的加密字符串","signature":"随机盐值字符串"}前端实现详解1. JavaScript 加密库实现依赖准备# 需要的加密库npminstallcrypto-js sm-crypto核心加密工具类importCryptoJSfrom'crypto-js';import{sm4}from'sm-crypto';/** * 动态加密工具类 */classDynamicEncryptUtil{// 密钥池(需要与后端保持一致,生产环境请自行替换)staticKEY_STRING_ARRAY=["a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6","f6e5d4c3b2a1f0e9d8c7b6a5f4e3d2c1","1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d","d5c4b3a2f1e0d9c8b7a6f5e4d3c2b1a0","0f1e2d3c4b5a6f7e8d9c0b1a2f3e4d5c","c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8","9a8b7c6d5e4f3a2b1c0d9e8f7a6b5c4d","4d5c6b7a8f9e0d1c2b3a4f5e6d7c8b9a"// 生产环境建议配置 16-32 个密钥];/** * 十六进制字符串转字节数组 */statichexStringToBytes(hex){constbytes=[];for(leti=0;ihex.length;i+=2){bytes.push(parseInt(hex.substr(i,2),16));}returnnewUint8Array(bytes);}/** * 获取随机整数 */staticgetRandInt(max){returnMath.floor(Math.random()*max);}/** * AES-CBC 加密 */staticaesEncryptCbc(keyBytes,ivBytes,plaintext){constkey=CryptoJS.lib.WordArray.create(keyBytes);constiv=CryptoJS.lib.WordArray.create(ivBytes);constencrypted=CryptoJS.AES.encrypt(plaintext,key,{iv:iv,mode:CryptoJS.mode.CBC,padding:CryptoJS.pad.Pkcs7});// 转换为字节数组constciphertext=encrypted.ciphertext;constbytes=newUint8Array(ciphertext.words.length*4);for(leti=0;iciphertext.words.length;i++){constword=ciphertext.words[i];bytes[i*4]=(word24)0xFF;bytes[i*4+1]=(word16)0xFF;bytes[i*4+2]=(word8)0xFF;bytes[i*4+3]=word0xFF;}returnbytes;}/** * SM4-CBC 加密 */staticsm4EncryptCbc(keyBytes,ivBytes,plaintext){constkeyHex=Array.from(keyBytes).map(b=b.toString(16).padStart(2,'0')).join('');constivHex=Array.from(ivBytes).map(b=b.toString(16).padStart(2,'0')).join('');// sm-crypto 库的 CBC 模式加密constencrypted=sm4.encrypt(plaintext,keyHex,{iv:ivHex,mode:'cbc'});returnthis.hexStringToBytes(encrypted);}/** * 计算 MD5 */staticmd5(dataBytes){constwordArray=CryptoJS.lib.WordArray.create(dataBytes);constmd5Hash=CryptoJS.MD5(wordArray);returnthis.hexStringToBytes(md5Hash.toString());}/** * 合并字节数组 */staticconcatByteArrays(...arrays){consttotalLength=arrays.reduce((sum,arr)=sum+arr.length,0);constresult=newUint8Array(totalLength);letoffset=0;for(constarrofarrays){result.set(arr,offset);offset+=arr.length;}returnresult;}/** * 主加密方法 */staticencrypt(data,groupIndex=0){if(!data)returnnull;constkeyLength=this.KEY_STRING_ARRAY.length;// 1. 随机选择密钥constprivateKeyIndex=this.getRandInt(keyLength);constprivateKey=this.hexStringToBytes(this.KEY_STRING_ARRAY[privateKeyIndex]);// 2. 随机选择 IVconstivKeyIndex=this.getRandInt(keyLength);consttokenIv=this.hexStringToBytes(this.KEY_STRING_ARRAY[ivKeyIndex]);// 3. 随机选择算法 (0: AES, 1: SM4)constalgorithmIndex=this.getRandInt(2);// 4. 执行加密letencryptText;switch(algorithmIndex){case0:encryptText=this.aesEncryptCbc(privateKey,tokenIv,data);break;case1:encryptText=this.sm4EncryptCbc(privateKey,tokenIv,data);break;default:encryptText=this.aesEncryptCbc(privateKey,tokenIv,data);}// 5. 构建加密包结构constheader=newUint8Array(32);header[