Web安全 - 基于 SM2/SM4 的前后端国产加解密方案详解

发布于:2025-07-12 ⋅ 阅读:(14) ⋅ 点赞:(0)


在这里插入图片描述


概述

随着信息安全法规日益严格,如《网络安全法》《数据安全法》和等保三级的落实,前后端通信中的敏感数据必须在传输层之上再加一层“国产加密”,才能满足合规与防护需求。接下来将以 SM2 与 SM4 为核心,详细剖析前端请求、后端处理及响应加密的全流程,并附示例代码,帮助读者快速落地。

一、背景与法规要求

  • 法规要求

    • 《网络安全法》《数据安全法》强调敏感数据加密存储与传输;
    • 等保三级对“重要信息系统”提出应用层加密需求。
  • 国产算法优势

    • SM2/SM4 系列为国家密码算法,已标准化并广泛验证;
    • 与通用算法(AES/RSA)兼容,便于渐进式升级。

二、算法选型

算法 类型 作用 备注
SM2 非对称 用于交换对称密钥 安全性强、计算效率适中
SM4 对称 用于加密具体业务数据 性能优异,适合大数据量传输
AES 对称 兼容场景下的通用方案 跨平台生态良好,可做备用或过渡方案

三、核心流程

阶段 前端操作 后端操作
初始化 拉取后端 SM2 公钥 生成 SM2 密钥对,并提供公钥接口
请求发送 1. 生成随机 SM4 密钥
2. 用 SM4 加密业务数据
3. 用 SM2 公钥加密 SM4 密钥
4. 组装请求体
1. 用私钥解密获得 SM4 密钥
2. 用 SM4 解密业务数据
3. 业务处理
响应返回 1. 用 SM4 加密响应 JSON
2. 可选:用私钥再 SM2 加密 SM4 密钥
3. 返回密文
前端解析 1. (可选)用 SM2 公钥/私钥解密 SM4 密钥
2. 用 SM4 解密响应体

在这里插入图片描述
在这里插入图片描述

四、前端实现要点(伪代码)

  1. 公钥获取与存储

    // 初始化时调用
    async function fetchPublicKey() {
      const { data: { sm2PublicKey } } = await axios.get('/api/crypto/pubkey');
      // 建议存储在 Pinia 或 context 中
      store.commit('crypto/setPublicKey', sm2PublicKey);
      // 如需持久化,可选 localStorage
      localStorage.setItem('sm2PublicKey', sm2PublicKey);
    }
    
  2. 一次性 SM4 密钥生成

    import SM4 from 'sm-crypto/lib/sm4';
    
    function generateSM4Key() {
      // 16 字节随机密钥
      return window.crypto.getRandomValues(new Uint8Array(16)).join('');
    }
    
  3. 业务数据与密钥加密

    import SM2 from 'sm-crypto/lib/sm2';
    
    async function encryptRequest(payload) {
      const sm4Key = generateSM4Key();
      const sm2Pub = store.state.crypto.sm2PublicKey;
      const encryptedData = SM4.encrypt(JSON.stringify(payload), sm4Key);
      const encryptedKey = SM2.doEncrypt(sm4Key, sm2Pub);
      return { encryptedKey, encryptedData };
    }
    
  4. 封装与发送

    async function sendSecureRequest(api, payload) {
      const { encryptedKey, encryptedData } = await encryptRequest(payload);
      return axios.post(api, { key: encryptedKey, data: encryptedData });
    }
    

五、后端实现要点(伪代码)

以 Spring Boot 为例:

推荐使用Interceptor,这里仅是演示

@RestController
@RequestMapping("/api/secure")
public class SecureController {
  @Value("${crypto.sm2.private-key}")
  private String sm2PrivateKey;

  @PostMapping("/process")
  public ResponseEntity<?> process(@RequestBody SecurePayload payload) {
    // 1. 解密 SM4 密钥
    String sm4Key = SM2.decrypt(payload.getKey(), sm2PrivateKey);
    // 2. 解密业务数据
    String json = SM4.decrypt(payload.getData(), sm4Key);
    BusinessRequest req = objectMapper.readValue(json, BusinessRequest.class);
    // 3. 业务处理...
    BusinessResponse resp = service.handle(req);
    // 4. 加密响应
    String respJson = objectMapper.writeValueAsString(resp);
    String encryptedData = SM4.encrypt(respJson, sm4Key);
    return ResponseEntity.ok(Map.of("data", encryptedData));
  }
}

Tip:如需双向加密,可在响应里同时返回 encryptedKey: SM2.encrypt(sm4Key, clientPubKey)

六、公钥存储策略

  • 短期存储:Vue/Pinia 中维护,方便统一调用;
  • 持久化localStorage/sessionStorage,防止页面刷新导致丢失;
  • 安全性:SM2 公钥非机密,可安全保存在前端。

七、全流程示例图

Frontend Backend GET /api/crypto/pubkey { sm2PublicKey } 生成 SM4 密钥 SM4 加密数据 SM2 加密 SM4 密钥 POST /process { key, data } SM2 解密 key → SM4Key SM4 解密 data → 业务数据 业务处理 SM4 加密响应 { data } SM4 解密 → 渲染 Frontend Backend

八、总结与最佳实践

  • 密钥管理:后端妥善存储 SM2 私钥,使用 HSM 或环境变量;
  • 性能优化:SM4 加解密速度快,SM2 仅用于短字符串,加密开销可接受;
  • 兼容性:可与 AES/RSA 并行使用,逐步迁移;
  • 安全防护:配合 HTTPS,防止中间人;做好重放攻击检测(如加时间戳、随机串)。

推荐

https://gitee.com/lab1024/smart-admin

SmartAdmin 由 中国·洛阳 1024创新实验室 基于SpringBoot2/3+Sa-Token+Mybatis-Plus 和 Vue3+Ant Design Vue+Uni-App+Uni-UI,并以 「高质量代码」为核心,「简洁、高效、安全」的快速开发平台。

国内首个满足《网络安全-三级等保》、《数据安全》 功能要求,支持登录限制、接口国产加解密、数据脱敏等一系列安全要求。

前端提供 JavaScript和TypeScript双版本,后端提供 Java8+SpringBoot2.X和Java17+SpringBoot3.X 双版本。

同时 重磅开源 开源六年来 千余家企业验证过且正在使用 的代码规范: 《高质量代码思想》、《Vue3规范》、《Java规范》 ,让大家在这浮躁的世界里感受到一股把代码写好的清流!同时又能节省大量时间,减少加班,快乐工作,保持谦逊,保持学习,热爱代码,更热爱生活 !

在这里插入图片描述


网站公告

今日签到

点亮在社区的每一天
去签到