芋道集成API 安全防护实战

芋道集成API 安全防护实战 概述最近在做一个国家机关的项目,要求的安全等级比较高。必须使用国密,且需要前后端传输加密,防重放以及参数签名。芋道项目原本有个前后端加密,但不是国密,我就把这次改造记录一下。本项目集成了 Guardian 轻量级 Spring Boot API 请求层防护框架,为所有 API 接口提供三层安全防护:安全层模块作用核心机制防重放攻击guardian-anti-replay防止攻击者截获合法请求后重复发送Timestamp + Nonce 双重校验参数签名guardian-sign防止请求参数被篡改SM3 哈希签名请求加解密guardian-encrypt防止请求/响应内容被窃听SM2+SM4 混合加密guardian也是我在问ai时,推荐给我的。我原来也不知道这个,其实还有一个选择就是sa-token,但改造成本太高,相当于把芋道的安全机制都破坏了,就没有选择。为什么需要 SM2 + SM3 + SM4算法类型解决的问题在本系统中的用途SM2非对称加密密钥安全分发加密 SM4 密钥,确保只有持有私钥的一方才能解密SM4对称加密高效数据加密加密请求体和响应体(比 SM2 快 100 倍以上)SM3哈希摘要防篡改对请求参数签名,验证数据完整性为什么不能只用一种?只用 SM2:性能差(非对称加密比对称加密慢 100-1000 倍),不适合大数据量只用 SM4:密钥分发问题,前后端共享密钥一旦泄露全部失效只用 SM3:只能验证完整性,不能加密数据SM2+SM4 混合加密就是国密版的 HTTPS(RSA+AES),SM3 签名则额外提供了防篡改能力。安全防护协议详解防重放攻击请求头:请求头说明示例X-Timestamp当前毫秒时间戳1782294676837X-Nonce每次请求唯一的 UUIDe26f2ac6-023b-4952-b730-500a2912c55a校验规则:时间戳与服务器时间差超过 60 秒 → 拒绝(请求过期)Nonce 在 60 秒内已存在 → 拒绝(重放攻击)参数签名(SM3)请求头:请求头说明X-SignSM3 签名值(64 字符 hex)X-Sign-Timestamp签名时间戳(毫秒)签名计算规则:参数排序:对请求参数按 key 字典序排序Body 处理:JSON body 递归按 key 排序后序列化拼接签名串:body={sorted_json}timestamp={ts}key={secret}SM3 哈希:sm3(签名串)→ 64 字符 hex 字符串示例:签名串 = body={"captchaVerification":"","password":"admin123","rememberMe":false,"username":"admin"}timestamp=1782294676837key=guardian-sign-default-secret X-Sign = sm3(签名串) = c0d6f8f62780dff462ac...请求加解密(SM2 + SM4)请求加密流程(客户端 → 服务端):① 准备明文请求体 ② 生成随机 SM4 密钥(16 个随机 ASCII 字符)→ dataKeyB64 = base64(randomKey) ③ SM2 公钥加密 SM4 密钥 → X-Encrypt-Key 请求头 ④ SM4 CBC 加密请求体 → {"encryptBody": "Base64(IV+密文)"}响应解密流程(服务端 → 客户端):① 读取响应头 X-Encrypt-Key → SM2 私钥解密 → 得到 dataKeyB64 ② 读取响应体 {"encryptBody": "..."} → SM4 CBC 解密 → 明文 JSONSM2 协议细节:加密:明文 → stringToHex → hex的UTF-8字节 → SM2Engine(C1C3C2) → Base64解密:Base64 → 字节 → SM2Engine(C1C3C2) → UTF-8字符串(即hex) → hexToString → 明文SM4 协议细节:加密:明文 → stringToHex → hex的UTF-8字节 → SM4 CBC PKCS7 → Base64(IV + 密文)解密:Base64 → 分离IV(16字节)和密文 → SM4 CBC PKCS7 → UTF-8字符串(即hex) → hexToString → 明文Filter 执行顺序请求进入 │ ▼ CacheRequestBodyFilter (order ≈ -2147483148) ← 缓存请求体,支持重复读取 │ ▼ DecryptFilter (order = -40000) ← SM2+SM4 解密请求体 │ GET/OPTIONS/无body请求自动跳过 ▼ AntiReplayFilter (order = -14000) ← 防重放校验 │ ▼ Spring Security FilterChain (order = -100) ← 身份认证 │ ▼ SignVerifyInterceptor (order = 4000) ← SM3 签名验证 │ ▼ Controller 业务逻辑 │ ▼ SignResultSignAdvice (order = 100) ← 响应签名 │ ▼ EncryptResponseAdvice (order = 300) ← SM2+SM4 加密响应配置指南后端配置Maven 依赖在yudao-dependencies/pom.xml中已配置版本管理:propertiesguardian.version1.11.0/guardian.version/propertiesdependencyManagementdependenciesdependencygroupIdio.github.biggg-guardian/groupIdartifactIdguardian-anti-replay-spring-boot-starter/artifactIdversion${guardian.version}/version/dependencydependencygroupIdio.github.biggg-guardian/groupIdartifactIdguardian-sign-spring-boot-starter/artifactIdversion${guardian.version}/version/dependencydependencygroupIdio.github.biggg-guardian/groupIdartifactIdguardian-encrypt-spring-boot-starter/artifactIdversion${guardian.version}/version/dependency/dependencies/dependencyManagementYAML 配置(application.yaml)点击展开完整配置guardian:# ═══════════ 防重放攻击 ═══════════anti-replay:enabled:truestorage:redismax-age:60nonce-ttl:60timestamp-header:X-Timestampnonce-header:X-Nonceresponse-mode:jsonlog-enabled:truefilter-order:-14000urls:-pattern:/admin-api/system/auth/login-pattern:/app-api/member/register-pattern:/share-api/ai/**exclude-urls:-/actuator/**-/admin-api/system/captcha/**# ═══════════ 参数签名(SM3) ═══════════sign:enabled:truesecret-key:${GUARDIAN_SIGN_SECRET:guardian-sign-default-secret}result-sign:truesign-header:X-Signtimestamp-header:X-Sign-Timestampmax-age:60response-mode:jsonlog-enabled:trueinterceptor-order:4000urls:-pattern:/admin-api/system/auth/loginalgorithm:sm3-pattern:/app-api/member/**algorithm:sm3-pattern:/share-api/ai/**algorithm:sm3exclude-urls:-/actuator/**-/admin-api/system/captcha/**# ═══════════ 请求解密(SM2+SM4) ═══════════decrypt:enabled:truekey:private-key:${GUARDIAN_SM2_PRIVATE_KEY:QosoNf43v2MNpt4hEQeYH05fvQKKA1/2O55Y/2TJHNU=}data:data-key-header:X-Encrypt-Keybody-alias:encryptBodykey-mode:DYNAMICresponse-mode:jsonlog-enabled:truefilter-order:-40000urls:-pattern:/admin-api/system/auth/loginkey-algorithm:SM2data-algorithm:SM4-pattern:/app-api/member/registerkey-algorithm:SM2data-algorithm:SM4-pattern:/admin-api/ai/**key-algorithm:SM2data-algorithm:SM4-pattern:/share-api/ai/**key-algorithm:SM2data-algorithm:SM4exclude-urls:-/actuator/**-/admin-api/system/captcha/**# SSE 流式接口-/admin-api/ai/llm/chat/chat-/admin-api/ai/llm/chat/noSessionChat-/admin-api/ai/agent/run/test/completion-/admin-api/ai/agent/chat/completion# 文件上传-/admin-api/ai/knowledgeDocs/uploadSave-/admin-api/ai/knowledgeDocs/chatUploadFile-/admin-api/ai/temporary-file/upload-/admin-api/ai/temporary-file/upload-batch-/admin-api/ai/minio-file/upload-/admin-api/ai/minio-file/upload-batch# 文件下载-/admin-api/ai/knowledgeDocs/downloadDocuments-/admin-api/ai/temporary-file/download-/admin-api/ai/doc/export/download# ═══════════ 响应加密(SM2+SM4) ═══════════encrypt:enabled:truekey:public-key:${GUARDIAN_SM2_PUBLIC_KEY:BCXEyH30HCR8I6wH7/AWM9VRFbIUoaXrBs420EraxIslN542SZ0dVJlT2a520w+uwSAvDiFokIj06Gk89nl2euY=}data:data-key-header:X-Encrypt-Keybody-alias:encryptBodykey-mode:DYNAMICresult-advice-order:300urls:# 与 decrypt 保持一致-pattern:/admin-api/system/auth/loginkey-algorithm:SM2data-algorithm:SM4-pattern:/app-api/member/registerkey-algorithm:SM2data-algorithm:SM4-pattern:/admin-api/ai/**key-algorithm:SM2data-algorithm:SM4-pattern:/share-api/ai/**key-algorithm:SM2data-algorithm:SM4exclude-urls:# 与 decrypt 保持一致-/actuator/**-/admin-api/system/captcha/**-/admin-api/ai/llm/chat/chat-/admin-api/ai/llm/chat/noSessionChat-/admin-api/ai/agent/run/test/completion-/admin-api/ai/agent/chat/completion-/admin-api/ai/knowledgeDocs/uploadSave-/admin-api/ai/knowledgeDocs/chatUploadFile-/admin-api/ai/temporary-file/upload-/admin-api/ai/temporary-file/upload-batch-/admin-api/ai/minio-file/upload-/admin-api/ai/minio-file/upload-batch-/admin-api/ai/knowledgeDocs/downloadDocuments-/admin-api/ai/temporary-file/download-/admin-api/ai/doc/export/downloadCORS 配置前端需要读取自定义响应头,已在YudaoWebAutoConfiguration中配置:config.addExposedHeader("X-Encrypt-Key");config.addExposedHeader("X-Sign");Spring Boot 3.x 适配说明Guardian 1.10.0 使用spring.factories注册自动配置(Spring Boot 2.x 机制),Spring Boot 3.x 不再读取。已在yudao-server中创建桥接文件:yudao-server/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports前端配置依赖pnpmaddsm-crypto环境变量(.env)# Guardian 请求层防护VITE_GUARDIAN_ENABLE=true# 防重放VITE_GUARDIAN_ANTI_REPLAY_ENABLE=true# 参数签名(SM3)VITE_GUARDIAN_SIGN_ENABLE=trueVITE_GUARDIAN_SIGN_SECRET=guardian-sign-default-secret# 请求加解密(SM2+SM4)VITE_GUARDIAN_ENCRYPT_ENABLE=true# SM2 公钥(Base64 格式,与后端 guardian.encrypt.key.public-key 一致)VITE_GUARDIAN_SM2_PUBLIC_KEY=BCXEyH30HCR8I6wH7/AWM9VRFbIUoaXrBs420EraxIslN542SZ0dVJlT2a520w+uwSAvDiFokIj06Gk89nl2euY=# SM2 私钥(Base64 格式,与后端 guardian.decrypt.key.private-key 一致,用于解密响应)VITE_GUARDIAN_SM2_PRIVATE_KEY=QosoNf43v2MNpt4hEQeYH05fvQKKA1/2O55Y/2TJHNU=核心文件文件说明src/utils/guardian.tsGuardian 三模块核心工具类src/config/axios/service.tsAxios 请求/响应拦截器(集成 Guardian)src/utils/fetchEventSourceWithAuth.tsSSE 流式请求(仅防重放+签名,不加密)前端开发注意事项前端的service.ts拦截器已自动处理所有安全措施,新写的接口请求不需要做任何额外处理。需要特殊处理的场景:场景处理方式SSE 流式接口传skipEncrypt: true,SSE 不支持加密文件上传自动跳过(multipart/form-data不加密)文件下载自动跳过(responseType: 'blob')不在后端 urls 配置中的接口自动跳过(后端不校验)示例:// 普通请求 — 自动加密签名,无需额外处理request.post({url:'/ai/agent/create',data:{name:'test'}})// SSE 流式请求 — 需要 skipEncryptfetchEventSourceWithAuth(url,