1. 项目背景与核心需求
最近在开发一个政务类项目时,客户明确要求所有敏感数据传输必须采用国密算法加密。经过技术调研,我们最终选择SM2作为非对称加密方案,配合Vue前端和SpringBoot后端实现全链路加密。这种组合既能满足合规性要求,又保持了良好的开发效率。
国密算法是由国内密码管理部门制定的商用密码标准体系,其中SM2基于椭圆曲线密码学(ECC),相比RSA在相同安全强度下密钥更短、计算更快。根据实际测试,在256位密钥长度下,SM2的加密速度比2048位RSA快约4倍。
2. 技术选型与准备工作
2.1 前端加密方案
Vue端采用sm-crypto库实现SM2加密,这个纯JavaScript实现的库具有以下优势:
- 零依赖,打包体积仅80KB
- 支持浏览器和Node.js环境
- 提供完整的SM2/SM3/SM4算法实现
安装命令:
bash复制npm install sm-crypto --save
2.2 后端解密方案
SpringBoot端使用BouncyCastle作为安全提供者:
xml复制<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.70</version>
</dependency>
需要特别注意的是,必须注册BC提供者:
java复制Security.addProvider(new BouncyCastleProvider());
3. 核心实现步骤
3.1 密钥对生成
推荐使用OpenSSL生成SM2密钥对:
bash复制openssl ecparam -genkey -name SM2 -out sm2-private.key
openssl ec -in sm2-private.key -pubout -out sm2-public.key
重要提示:私钥文件必须严格保密,建议存储时使用密码二次加密
3.2 Vue前端加密实现
封装加密工具类:
javascript复制import { sm2 } from 'sm-crypto'
const publicKey = '04...' // 填入公钥内容
export default {
encrypt(data) {
const cipherMode = 1 // C1C3C2模式
return sm2.doEncrypt(JSON.stringify(data), publicKey, cipherMode)
}
}
3.3 SpringBoot后端解密实现
创建解密工具类:
java复制public class SM2Util {
private static final String ALGORITHM = "SM2";
public static String decrypt(String encrypted, PrivateKey privateKey) {
Cipher cipher = Cipher.getInstance(ALGORITHM, "BC");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] decoded = Base64.getDecoder().decode(encrypted);
return new String(cipher.doFinal(decoded));
}
}
4. 性能优化与安全加固
4.1 加密性能优化
实测发现,长文本加密时会出现性能瓶颈。解决方案:
- 对超过1KB的数据先进行GZIP压缩
- 采用分段加密策略
- 前端使用Web Worker进行异步加密
优化后性能对比:
| 数据大小 | 原始耗时 | 优化后耗时 |
|---|---|---|
| 1KB | 120ms | 45ms |
| 10KB | 980ms | 210ms |
4.2 防重放攻击
建议在加密数据中加入时间戳和随机数:
javascript复制const payload = {
data: {...},
timestamp: Date.now(),
nonce: Math.random().toString(36).substring(2)
}
后端验证逻辑:
java复制if(Math.abs(System.currentTimeMillis() - timestamp) > 5000) {
throw new RuntimeException("请求已过期");
}
5. 常见问题排查
5.1 解密失败问题
典型错误现象:
code复制org.bouncycastle.crypto.InvalidCipherTextException: invalid cipher text
排查步骤:
- 确认前后端使用的加密模式一致(建议统一使用C1C3C2)
- 检查公钥/私钥是否配对
- 验证Base64编码是否正确
5.2 中文乱码问题
解决方案:
java复制// 在解密后指定字符集
return new String(cipher.doFinal(decoded), StandardCharsets.UTF_8);
6. 完整交互流程示例
- 前端获取用户输入数据
- 添加时间戳和随机数
- 使用SM2公钥加密
- 通过HTTPS发送到后端
- 后端用私钥解密
- 验证时间戳有效性
- 处理业务逻辑
关键代码片段:
javascript复制// Vue组件
submitForm() {
const encrypted = encryptService.encrypt(this.formData)
axios.post('/api/submit', { data: encrypted })
}
java复制// SpringBoot Controller
@PostMapping("/submit")
public Response handle(@RequestBody EncryptedData data) {
String decrypted = SM2Util.decrypt(data.getData(), privateKey);
// ...业务处理
}
在实际项目中,我们还添加了加密数据签名验证环节,使用SM3算法生成消息摘要,进一步确保数据完整性。整个方案上线后通过了第三方安全审计,各项指标均达到政务系统安全要求。