2.3.1.知识包推送与集群同步安全配置
适用对象:架构师、系统维护人员 适用范围:知识包匿名推送端点(
KnowledgePackageReceiverServlet)与集群节点同步端点(DynamicServletHandler) 说明:本节仅描述配置项,不含实现细节。客户端与服务端必须同时升级,无向后兼容。 关联章节:2.3.系统默认参数覆盖、3.8.集群管理、11.5.1.服务端集群搭建
1. 概述
对知识包推送与集群同步端点做端到端的 HMAC-SHA256 请求签名加固,替换原有的明文 _u/_p 弱凭证校验。核心变化:
- 请求通过 HTTP 头传递签名信息(
X-Urule-*),不进入 URL,避免落入访问日志。 - 接收端启用防重放(时间戳窗口 + nonce 去重)、body 大小限流、Zip Slip 防护、异常不回显。
urule.pushSignSecret为必填项,缺失时接收端启动失败。
2. 配置项一览
| 配置项 | 必填 | 默认值 | 说明 |
|---|---|---|---|
urule.pushSignSecret |
是 | 无(内置默认常量仅用于告警检测) | 签名密钥,HMAC-SHA256 计算所用 secret |
urule.pushBodyMaxSize |
否 | 104857600(约 100 MB) |
接收端单次请求 body 大小上限,超出直接拒绝 |
urule.pushSignTimeWindow |
否 | 300000(毫秒,即 5 分钟) |
时间戳窗口;nonce 去重 TTL 与窗口一致 |
3. 配置读取优先级
每个属性按以下顺序解析,高优先级覆盖低优先级:
1. JVM 系统属性(-D,最高优先)
2. urule.properties 文件(PropertyConfigurer)
3. 内置默认值
示例:
# 方式一:启动参数(系统级,最高优先)
-Durule.pushSignSecret=your-strong-secret
-Durule.pushBodyMaxSize=209715200
-Durule.pushSignTimeWindow=600000
# 方式二:urule.properties 文件
urule.pushSignSecret=your-strong-secret
urule.pushBodyMaxSize=209715200
urule.pushSignTimeWindow=600000
提示:两种配置方式均可,系统属性
-D可临时覆盖文件配置,便于运维在不变更发布包的情况下调整阈值。
4. 各配置项说明
4.1 urule.pushSignSecret(必填)
- 客户端(console 推送端)与接收端(core 接收端)必须配置为相同值。
- 为空:视为必填缺失,接收端
Servlet.init启动时 SEVERE 告警并启动失败(快速失败)。 - 等于内置默认常量:启动时 SEVERE 告警(提示未修改默认口令)。
- 建议:使用足够长度的随机密钥,通过
-D注入或妥善保管urule.properties文件权限。
4.2 urule.pushBodyMaxSize(可选)
- 接收端一次性读取并校验 body 的上限,单位为字节。
- 超过该值的请求直接拒绝,避免无限读取。
- 默认约 100 MB;如需推送更大知识包,按实际需求上调。
4.3 urule.pushSignTimeWindow(可选)
- 时间戳窗口(毫秒),用于防重放校验。
- 接收端拒绝窗口外(默认 ±5 分钟)的请求。
- nonce 去重集合的 TTL 与此窗口一致;多实例部署时,时间戳窗口为首要防重放防线。
5. 签名机制(运维关注点)
签名头(请求头,不进入 URL):
| Header | 含义 | | --- | --- | |
X-Urule-Timestamp| 请求时间戳(毫秒) | |X-Urule-Nonce| 一次性随机串,用于去重 | |X-Urule-Body-Digest|SHA-256(body)的 hex 摘要 | |X-Urule-Sign|HMAC-SHA256(secret, timestamp|nonce|bodyDigestHex)的 hex |校验内容(接收端
PushSignature.verify):签名正确性 + 时间戳窗口 + nonce 去重 + body 大小。- 校验失败 / 异常仅返回通用文案(如「签名校验失败」「请求体过大」「服务器内部错误」),完整堆栈仅记录服务端日志,不回显给客户端。
6. 部署检查清单
- [ ] 客户端与接收端同时部署新版本(不兼容旧版
_u/_p校验)。 - [ ] 所有节点的
urule.pushSignSecret配置一致且非默认/非空。 - [ ] 多实例部署时各节点时钟同步(保障时间戳窗口校验有效)。
- [ ] 如知识包体积较大,确认
urule.pushBodyMaxSize已按需调整。 - [ ] 接收端启动日志无 SEVERE 级别「默认口令 / 缺失 secret」告警。
- [ ] 集群同步链路(
DynamicServletHandler)与推送链路均已完成签名改造。
7. 备注
- 受影响模块:
urule-core-pro(接收端校验 + 共享签名工具 + Zip Slip 修复)、urule-console-pro(推送端签名 + 集群端点校验)。urule-pro-boot2/boot3复用 core-pro 的 Servlet,无需额外注册。 - 兼容 JDK 1.8 运行环境,加解密仅使用 JDK 自带
javax.crypto.Mac与java.security.MessageDigest,无新增第三方依赖;该方案同样可在 JDK 21/23 下运行(详见第 8 节)。 requestRemoteJars/remoteCheck(client→repo 拉取链路)不在本次加固范围,仍保留原有_u/_p机制。
8. JDK 21/23 兼容性说明
本节供运维/架构在决定升级运行 JDK 版本时参考。结论:当前 HMAC-SHA256 + SHA-256 方案在 JDK 21/23 下完全兼容,无需为算法本身做任何改动。
8.1 算法层兼容(无需改动)
当前仅使用 JDK 8 时代即存在、且在新版 JDK 中仍长期保留于 java.base 的核心 API:
| 用途 | 使用的 API | 在 JDK 21/23 的状态 |
|---|---|---|
| HMAC 计算 | javax.crypto.Mac |
java.base,始终可用 |
| body 摘要 | java.security.MessageDigest |
java.base,始终可用 |
| 发送请求 | HttpURLConnection / setRequestProperty |
java.net(java.base),未废弃 |
| Zip Slip 校验 | File.getCanonicalPath() |
java.base,仍可用 |
| 属性读取 | System.getProperty |
核心 API,无变化 |
签名计算显式使用 UTF_8 字符集(如 secret.getBytes(UTF_8)),规避了 JDK 18+ 默认字符集改为 UTF-8(JEP 400)带来的跨版本行为差异,跨 JDK 行为一致。
8.2 模块系统(JPMS)不会拦截
即便应用以 JPMS 模块化方式运行(module-info.java),javax.crypto、java.security、java.net 均位于 java.base,对任意模块默认可见,无需额外 requires。不会出现"升级 JDK 后编译报模块不可访问"的问题。
8.3 需注意的环境级差异(非算法问题)
- Security Manager 移除(JDK 17+,JEP 411):当前签名/摘要逻辑不依赖 SM,无影响。
- TLS 默认值变化(JDK 11+,仅 HTTPS 推送链路):若推送走 HTTPS,新版 JDK 默认启用 TLS 1.3、禁用 TLS 1.0/1.1,且 JDK 16+ 默认禁用 SHA-1 签名证书链。若接收端仍用老 TLS 或 SHA-1 证书,会连接失败——与 HMAC 逻辑无关,需运维核对对端配置。
- 编译目标约束:项目仍以 JDK 1.8 为目标(字节码 major 52),可在任何更高版本 JVM 上运行;只需继续遵守"不引入 JDK 9+ API"的约束(如不使用
Path.toRealPath)。
8.4 验证清单
- [ ] 算法层无需改动:HMAC-SHA256 / SHA-256 在 21/23 均内置默认可用(无限强度策略自 JDK 8u161 起默认开启)。
- [ ] 确认未使用
javax.xml.bind、CORBA、sun.misc.*等 JDK 11+ 已移除的包(本方案未涉及)。 - [ ] 若启用 HTTPS 推送,核对接收端 TLS 版本与证书(避免 SHA-1/老 TLS 被新版 JDK 拒绝)。
- [ ] 若以 JPMS 模块运行,无需为 crypto/network 额外
requires(已在java.base)。 - [ ] 保持
getBytes(UTF_8)等显式字符集写法,避免默认字符集差异。