核心思路是利用jpms的exports与opens机制从源头隔离访问:仅导出必要api包,禁止未声明包被引用;opens必须限定目标模块,严禁无约束开放;切断隐式依赖链,禁用--add-opens等宽泛授权,确保模块边界严格生效。
核心思路是利用 java 模块系统(jpms)的显式导出(exports)与选择性开放(opens)机制,从源头切断不受信任模块对本地变量的访问路径。仅靠类访问修饰符(如 private)在模块化环境下已不足够——关键在于模块边界本身是否被严格定义。
只导出真正需要对外暴露的包
未被 exports 声明的包,即使内部类是 public,其他模块也无法编译期引用或运行时加载其类型。这是最基础、最有效的隔离层。
- 在
module-info.java中,仅导出接口或 DTO 包,例如:exports com.example.api; - 坚决避免导出含敏感字段或逻辑实现的包,如
com.example.internal、com.example.config - 不要使用
open module xxx { ... }全局开放模块——这等同于放弃模块封装
禁止反射越权:慎用 opens,且必须限定目标模块
opens 是唯一允许反射访问的合规通道,但它不是“开放给所有人”,而是“开放给指定模块”。若不限定,就等于为攻击者铺路。
- 需要反射支持时(如序列化框架),写法必须是:
opens com.example.model to com.fasterxml.jackson.databind; - 绝不能写成:
opens com.example.model;(无目标)或opens com.example.*;(通配危险) - 检查第三方库是否在
requires列表中——没声明依赖的模块,连反射入口都进不来
切断隐式依赖链,防止“依赖传递越权”
不受信任的模块可能通过你依赖的中间库间接获得访问权限。JPMS 的 transitive 和模块可见性规则可阻断这类路径。
- 避免使用
requires transitive xxx;引入你不直接使用的模块,尤其对非官方或低信誉库 - 若某工具库(如某个日志适配器)要求你
opens内部包,优先评估是否可替换为标准模块(如java.logging) - 用
jdeps --list-deps定期检查实际依赖图,识别未声明却偷偷加载的模块
配合运行时策略强化边界
模块描述只是契约,JVM 还需执行它。确保环境不降级绕过保护:
- 启动时禁用非法访问选项:
--illegal-access=deny(Java 16+ 默认启用,无需额外加;旧版本务必显式设置) - 不使用
--add-opens java.base/java.lang=ALL-UNNAMED等宽泛授权,除非调试且明确知晓风险 - 生产环境用
jlink构建最小化运行镜像,剔除未声明依赖的模块,从物理层面消除越权可能










