
Spring Boot 3.x Vue 3 国密SM2/SM4混合加密实战5步构建金融级安全通道在金融、政务等高安全需求场景中数据传输安全是系统设计的核心命题。国密算法作为我国自主研发的密码体系正在逐步替代国际通用加密标准。本文将带您实现基于Spring Boot 3.x和Vue 3的SM2非对称与SM4对称混合加密方案这种非对称加密会话密钥对称加密业务数据的模式兼具安全性与性能优势。1. 混合加密架构设计现代加密体系通常采用混合加密方案其核心优势在于SM2非对称加密用于密钥交换解决密钥分发难题SM4对称加密用于业务数据加密处理效率比非对称加密高100倍以上典型通信流程如下前端生成随机SM4密钥会话密钥使用后端SM2公钥加密SM4密钥使用SM4密钥加密业务数据后端用SM2私钥解密获取SM4密钥用SM4密钥解密业务数据sequenceDiagram participant Frontend as 前端(Vue 3) participant Backend as 后端(Spring Boot 3) Frontend-Backend: 请求SM2公钥 Backend--Frontend: 返回公钥 Frontend-Frontend: 生成随机SM4密钥 Frontend-Frontend: 用SM2公钥加密SM4密钥 Frontend-Frontend: 用SM4密钥加密请求数据 Frontend-Backend: 发送加密后的SM4密钥加密数据 Backend-Backend: 用SM2私钥解密SM4密钥 Backend-Backend: 用SM4密钥解密数据 Backend-Backend: 处理业务逻辑 Backend-Backend: 用SM4密钥加密响应数据 Backend--Frontend: 返回加密响应 Frontend-Frontend: 用SM4密钥解密响应2. 后端核心实现2.1 依赖配置使用Hutool工具包简化国密算法操作!-- pom.xml -- dependency groupIdcn.hutool/groupId artifactIdhutool-all/artifactId version5.8.16/version /dependency dependency groupIdorg.bouncycastle/groupId artifactIdbcprov-jdk18on/artifactId version1.72/version /dependency2.2 密钥对管理建议采用单例模式管理密钥对// SM2KeyHolder.java Component public class SM2KeyHolder { private final SM2 sm2; private final String publicKey; public SM2KeyHolder() { this.sm2 SmUtil.sm2(); this.publicKey HexUtil.encodeHexStr( ((BCECPublicKey) sm2.getPublicKey()).getQ().getEncoded(false) ); } public String getPublicKey() { return publicKey; } public String decryptSM4Key(String encryptedKey) { return StrUtil.utf8Str(sm2.decryptFromBcd(encryptedKey, KeyType.PrivateKey)); } }2.3 加密服务实现// CryptoService.java Service public class CryptoService { Autowired private SM2KeyHolder keyHolder; // SM4加密 public String encryptWithSM4(String data, String sm4Key) { SymmetricCrypto sm4 SmUtil.sm4(sm4Key.getBytes(StandardCharsets.UTF_8)); return sm4.encryptHex(data); } // SM4解密 public String decryptWithSM4(String encryptedData, String sm4Key) { SymmetricCrypto sm4 SmUtil.sm4(sm4Key.getBytes(StandardCharsets.UTF_8)); return sm4.decryptStr(encryptedData); } }2.4 全局拦截器配置自动处理加密请求和解密响应// EncryptInterceptor.java public class EncryptInterceptor implements HandlerInterceptor { Autowired private CryptoService cryptoService; Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { if (handler instanceof HandlerMethod) { HandlerMethod method (HandlerMethod) handler; if (method.hasMethodAnnotation(EncryptedRequest.class)) { String encryptedSM4Key request.getHeader(X-SM4-Key); String encryptedBody IOUtils.toString(request.getInputStream(), StandardCharsets.UTF_8); String sm4Key keyHolder.decryptSM4Key(encryptedSM4Key); String decryptedBody cryptoService.decryptWithSM4(encryptedBody, sm4Key); // 将解密后的数据重新放入请求流 byte[] bytes decryptedBody.getBytes(StandardCharsets.UTF_8); request new ContentCachingRequestWrapper(request, bytes); } } return true; } Override public void postHandle(/* 参数省略 */) { if (method.hasMethodAnnotation(EncryptedResponse.class)) { String sm4Key (String) request.getAttribute(sm4Key); String originalResponse response.getContentAsString(); String encryptedResponse cryptoService.encryptWithSM4(originalResponse, sm4Key); response.setContentType(text/plain); response.getWriter().write(encryptedResponse); } } }3. 前端核心实现3.1 安装加密库npm install sm-crypto --save npm install types/sm-crypto --save-dev3.2 加密工具类// crypto-utils.ts import { sm2, sm4 } from sm-crypto const SM2_CIPHER_MODE 0 // C1C2C3格式 export class CryptoService { private sm4Key: string private serverPublicKey: string // 初始化服务 async init(publicKeyEndpoint: string) { const response await fetch(publicKeyEndpoint) this.serverPublicKey (await response.text()).trim() this.generateSM4Key() } // 生成随机SM4密钥 private generateSM4Key() { this.sm4Key Array.from({ length: 32 }, () Math.floor(Math.random() * 16).toString(16) ).join() } // 加密SM4密钥 getEncryptedSM4Key(): string { return 04 sm2.doEncrypt(this.sm4Key, this.serverPublicKey, SM2_CIPHER_MODE) } // 加密请求数据 encryptRequestData(data: any): string { const dataStr typeof data string ? data : JSON.stringify(data) return sm4.encrypt(dataStr, this.sm4Key) } // 解密响应数据 decryptResponseData(encryptedData: string): any { const decrypted sm4.decrypt(encryptedData, this.sm4Key) try { return JSON.parse(decrypted) } catch { return decrypted } } }3.3 Axios拦截器配置// http.ts import axios from axios import { CryptoService } from ./crypto-utils const crypto new CryptoService() await crypto.init(/api/public-key) const instance axios.create({ baseURL: /api, headers: { Content-Type: text/plain } }) // 请求拦截 instance.interceptors.request.use(config { if (config.data config.headers?.[X-Encrypt-Request]) { config.headers[X-SM4-Key] crypto.getEncryptedSM4Key() config.data crypto.encryptRequestData(config.data) } return config }) // 响应拦截 instance.interceptors.response.use(response { if (response.config.headers?.[X-Encrypt-Response]) { response.data crypto.decryptResponseData(response.data) } return response }) export default instance4. 性能优化策略4.1 会话密钥复用建议采用会话级SM4密钥复用策略前端通过localStorage缓存SM4密钥加密存储每次请求携带相同的加密后SM4密钥后端建立密钥缓存TTL 30分钟// 后端缓存实现示例 Cacheable(value sm4Keys, key #encryptedKey) public String getSM4Key(String encryptedKey) { return keyHolder.decryptSM4Key(encryptedKey); }4.2 批量加密优化对于大批量数据加密建议对大文件分块处理每1MB一个块采用并行流加密使用Zero-Copy技术减少内存拷贝// 文件分块加密示例 public void encryptLargeFile(Path source, Path target, String sm4Key) { try (InputStream in Files.newInputStream(source); OutputStream out Files.newOutputStream(target)) { byte[] buffer new byte[1024 * 1024]; int bytesRead; SymmetricCrypto sm4 SmUtil.sm4(sm4Key.getBytes()); while ((bytesRead in.read(buffer)) ! -1) { byte[] encrypted sm4.encrypt(Arrays.copyOf(buffer, bytesRead)); out.write(encrypted); } } }5. 安全增强措施5.1 防重放攻击在加密数据包中添加时间戳和随机数// 前端增强加密 function buildSecurePayload(data: any) { return { _timestamp: Date.now(), _nonce: Math.random().toString(36).substring(2, 10), data } } // 使用时 const rawData buildSecurePayload({ foo: bar }) const encrypted crypto.encryptRequestData(rawData)5.2 密钥轮换方案建议的密钥轮换策略密钥类型轮换周期轮换方式SM2密钥对1年手动更换SM4会话密钥30分钟自动刷新SM4文件加密密钥单次使用每次生成实现自动密钥轮换的Spring Scheduler示例Scheduled(fixedRate 30 * 60 * 1000) public void clearKeyCache() { cacheManager.getCache(sm4Keys).clear(); }5.3 完整性和验证建议在加密数据中添加HMAC-SM3校验// 后端校验示例 public boolean verifyData(String data, String sm4Key, String signature) { String actualSign SmUtil.sm3(sm4Key data); return actualSign.equals(signature); }在Vue中实现对应的签名生成import { sm3 } from sm-crypto function signData(data: string, key: string): string { return sm3(key data) }通过这套混合加密方案我们成功在Spring Boot 3和Vue 3技术栈上构建了符合国密标准的安全通信通道。实际部署时建议结合硬件加密模块如密码机来保护根密钥安全并定期进行安全审计。