# 隐写术与Spring轻量分布式安全框架实践 **Repository Path**: float-like-dream/http-secure-common ## Basic Information - **Project Name**: 隐写术与Spring轻量分布式安全框架实践 - **Description**: 隐写术与Spring轻量分布式安全框架实践 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-08-19 - **Last Updated**: 2025-09-29 ## Categories & Tags **Categories**: Uncategorized **Tags**: SpringBoot, SSH, 隐写术, Wasm, web安全 ## README # **http-secure-common 安全通信框架设计与开发文档** --- ## 一、概述 `http-secure-common` 是一个基于 Spring Boot 的 **端到端安全通信框架**,专为 Web 应用设计,提供以下核心能力: - **请求/响应内容加密**(SM4 对称加密) - **密钥动态协商与轮换**(SM2 非对称加密) - **防重放攻击与请求唯一性验证** - **IP 地址绑定与设备指纹校验** - **隐写式密钥分发**(PNG/TTF/Binary 伪装) - **审计日志与拦截事件通知** - **可插拔式存储后端**(Redis / 本地内存) 该框架适用于对安全性要求较高的金融、政务、企业级系统,支持国产密码算法(SM2/SM3/SM4),符合国密标准。 --- ## 二、架构设计 ### 2.1 密钥交互逻辑 - Step 1:客户端请求伪装公钥 - 客户端调用伪装接口(如 POST /pubkey.png) - 该接口被 @DisguiseAPI(DisguiseEnum.PNG) 标记 - 服务端: - 生成一对 SM2 密钥(pubKey_S, priKey_S) - 将 pubKey_S 通过 LSB 隐写术 嵌入到返回的 PNG 图片中 - 将 priKey_S 以 SM3(pubKey_S) 为 key 存入 SecureKeyStore,有效期默认 60 秒 - Step 2:客户端提取服务端公钥 - 客户端收到 PNG 文件后,调用 Disguise.getKeyByImg() - 从图片 LSB 位中提取出 pubKey_S(字符串形式) - Step 3:客户端生成密钥对并加密 - 客户端调用 SM2.generateKeyPairHex() 生成自己的密钥对 (pubKey_C, priKey_C) - 使用 pubKey_S 对 pubKey_C 进行 SM2 加密,得到密文 encPubKey_C - Step 4:发送密钥交换请求 - 客户端向 /change(默认路径)发送 POST 请求: ```http request POST /change HTTP/1.1 Content-Type: text/plain x-server-digest: SM3(pubKey_S) x-client-digest: SM3(pubKey_C) x-browser-sign: SM3(设备指纹) ``` - Step 5:服务端处理交换请求 - 服务端通过 x-server-digest 找到对应的 priKey_S - 用 priKey_S SM2 解密 encPubKey_C,得到 pubKey_C - 验证 SM3(pubKey_C) == x-client-digest - 验证 IP 与 Step 1 一致(若 verifyRequestRemote=true) - 保存: - CLIENT_PUB_KEY = pubKey_C - BROWSER_IV = x-browser-sign(用于 SM4 的 IV) - 生成 SM4 密钥 sm4Key - 用 pubKey_C SM2 加密 sm4Key,返回密文 - Step 6:客户端获取 SM4 密钥 - 客户端收到响应后,用 priKey_C SM2 解密,得到 sm4Key - 后续所有带 @RequestEnc 的请求: - 使用 sm4Key + 设备指纹SM3前32位 作为 IV,SM4-CBC 加密字段 - 生成签名:SM3(所有字段拼接 + 时间戳),并加密后放入 sign 字段 ### 2.2 核心组件说明 | 组件 | 作用 | |--------------------------------|---------------------------| | `@RequestEnc` / `@ResponseEnc` | 标记需加解密的接口 | | `@DisguiseAPI` | 标记伪装接口(返回含公钥的 PNG/TTF 等) | | `SecureRequestFilter` | 拦截加密请求,自动解密并验证 | | `KeySwitcher` | 密钥协商核心逻辑(SM2 生成、SM4 分发) | | `SecureKeyStore` | 会话隔离的密钥存储(支持 Redis) | | `RepeatValidator` | 防重放攻击(基于时间戳+签名) | | `MappingUtil` | 动态获取当前请求对应的 Controller 方法 | | `SMHelper` | 国密算法封装(SM2/SM3/SM4) | | `Steganography` | 隐写术实现(图片/字体/二进制嵌入公钥) | --- ## 三、核心优势能力 ### ✅ 1. **端到端国密加密** - 请求体/表单字段使用 **SM4-CBC** 加密,密钥通过 **SM2** 安全分发。 - 响应内容可自动加密,防止中间人窃听。 ### ✅ 2. **动态密钥协商 + 自动轮换** - 每次会话独立密钥,支持配置轮换周期(默认 300 秒)。 - 轮换时通过响应头 `X-EXCHANGE-KEY` 无感推送新密钥。 ### ✅ 3. **防重放 & 防伪造** - 请求携带 **时间戳 + SM3 签名**。 - 服务端验证:**时间窗口(默认 60s) + 签名唯一性**。 - 支持高并发场景下的重复请求拦截(`MappedRepeatValidator` 基于内存映射文件,单机高性能)。 ### ✅ 4. **IP 与设备绑定** - 可选开启 `verifyRequestRemote=true`,强制请求 IP 与密钥交换时一致。 - 使用 **Canvas 指纹 + 浏览器特征** 生成 SM4 的 IV(初始化向量),实现设备级绑定。 ### ✅ 5. **隐写式密钥分发(Anti-Detection)** - 公钥可伪装为: - PNG 图片(LSB 隐写) - TTF 字体文件(glyf 表隐写) - 任意二进制文件 - 客户端通过 `Disguise` 类自动提取公钥,**绕过网络审查或 WAF 检测**。 ### ✅ 6. **事件驱动 & 可扩展** - 提供 `AuditSecureListener`:拦截非法请求时推送审计事件。 - 提供 `KeyExchangeListener`:密钥交换成功时通知业务系统(可用于日志、风控)。 ### ✅ 7. **存储后端灵活切换** - 默认使用 **HttpSession + 本地 Map**。 - 若配置 `spring.data.redis.host`,自动切换为 **Redis 存储**,支持集群部署。 --- ## 四、快速上手教程 ### 步骤 1:添加依赖(Maven) ```xml your.group http-secure-common 1.0.0 ``` > 注:需自行编译或部署该模块到私有仓库。 --- ### 步骤 2:启用安全配置(application.yml) ```yaml secure: request: link-valid-time: 60 # 请求有效期(秒) key-rotation-time: 300 # SM4 密钥轮换周期(秒) verify-request-remote: true # 是否校验IP一致性 same-session-exchange-diff-key: true request-rejct-http-code: 401 api: key-exchange-path: /change key-rotation-path: /rotation # 可选:启用 Redis 存储 spring: redis: host: localhost port: 6379 ``` --- ### 步骤 3:编写安全接口 ```java @RestController @RequestMapping("/api") public class SecureController { // 请求和响应均加密 @PostMapping("/user") @RequestEnc @ResponseEnc public Map createUser(@RequestBody Map body) { // body 已自动解密 System.out.println("Decrypted body: " + body); return Map.of("status", "ok", "data", body); } // 伪装接口:返回含公钥的 PNG @DisguiseAPI(DisguiseEnum.PNG) @PostMapping("/pubkey.png") public Resource getPubkey() { return new FileSystemResource("path/to/cover.png"); } } ``` --- ### 步骤 4:前端集成(浏览器) ```html ``` --- ### 步骤 5(可选):自定义拦截行为 ```java @Component public class MyRejectHandler implements RequestRejectHandler { @Override public void rejectRequestAfter(HttpServletResponse response, Exception exception) { response.setStatus(403); response.getWriter().write("{\"error\": \"Security check failed\"}"); } } ``` --- ### 步骤 6(可选):监听密钥事件 ```java @Component public class MyKeyListener implements KeyExchangeListener { @Override public void onKeyExchange(String sessionId, String sm4Key) { System.out.println("Session " + sessionId + " got key: " + sm4Key); // 可存入数据库或日志系统 } @Override public void onSessionClosed(HttpSession session) { // 清理资源 } } ``` --- ## 五、安全建议 1. **不要关闭 `verifyRequestRemote`**,否则可能遭受中间人攻击。 2. **`linkValidTime` 不宜过长**,建议 ≤ 60 秒。 3. **生产环境务必启用 Redis**,避免单机内存溢出。 4. **伪装文件应定期更换**,防止被识别为固定模式。 5. **前端 SDK 应混淆压缩**,防止逆向分析。 ---