Java 9引入的模块系统通过module-info文件定义模块的依赖关系和访问权限,能够有效限制不受信任的依赖对本地变量的越权访问,从架构层面提升应用的安全性。

module-info的核心作用
module-info是模块的描述文件,放在模块的根目录下,用于声明模块的名称、依赖的其他模块、对外暴露的包以及允许反射访问的包。模块的封装特性默认会隐藏内部实现细节,外部模块无法直接访问未显式导出的包,这是限制越权访问的基础。
限制越权访问的核心配置规则
1. 最小化导出范围
使用exports指令仅导出需要对外提供服务的包,未导出的包中的类、接口以及其内部的本地变量,外部模块都无法直接访问。
例如模块内部有一个存储敏感数据的工具类,放在com.example.internal包下,该包不导出,不受信任的依赖就无法直接引用该包下的类,自然无法获取其中的本地变量。
2. 谨慎使用opens指令
opens指令用于允许其他模块通过反射访问指定包的内容,包括私有字段和本地变量。对于不受信任的依赖,应避免开放包含敏感本地变量的包。
如果确实需要反射支持,可使用opens ... to ...语法指定仅允许受信任的模块进行反射访问,示例如下:
module com.example.core {
// 仅导出对外提供服务的包
exports com.example.api;
// 仅允许受信任的模块com.example.trusted反射访问内部包
opens com.example.internal to com.example.trusted;
}
3. 明确依赖范围
使用requires指令声明模块需要的依赖,仅引入必要的受信任依赖,避免引入不必要的第三方依赖。对于不受信任的依赖,可通过不声明requires或者将其放在模块路径外的方式,使其无法访问模块内容。
本地变量保护的实际示例
假设我们有一个核心模块com.example.payment,内部有一个处理支付信息的类,包含敏感本地变量:
package com.example.internal.payment;
public class PaymentProcessor {
// 敏感本地变量,存储支付密钥
private String paymentKey;
public PaymentProcessor(String key) {
this.paymentKey = key;
}
public void process() {
// 支付处理逻辑
}
}
对应的module-info配置如下,确保不受信任的依赖无法访问该敏感变量:
module com.example.payment {
// 仅导出支付相关的接口包,不包含内部实现包
exports com.example.api.payment;
// 不导出com.example.internal.payment包,也不开放该包给不受信任的依赖
// 仅引入受信任的依赖
requires com.example.secure_util;
}
此时,不受信任的依赖即使引入了com.example.payment模块,也无法访问com.example.internal.payment包下的PaymentProcessor类,更无法获取其中的paymentKey本地变量。
常见注意事项
- 不要为了开发方便随意导出所有包,始终遵循最小权限原则。
- 反射相关的opens指令要严格限制目标模块,避免开放给所有模块。
- 定期审查module-info配置,移除不再需要的导出和开放声明。
- 对于必须使用的第三方依赖,可将其封装在独立的受信任模块中,通过模块边界隔离风险。
模块系统的访问控制是编译时和运行时的双重约束,即使不受信任的依赖尝试通过类加载器等方式绕过,模块系统也会在访问时抛出IllegalAccessError等异常,阻止越权访问。
总结
通过合理配置module-info的导出、开放和依赖声明,结合模块的默认封装特性,能够有效限制不受信任的依赖对本地变量的越权访问。开发者需要在设计模块时明确边界,严格控制权限范围,才能充分发挥Java模块系统的安全价值。
module-infoJava_module依赖访问控制本地变量保护修改时间:2026-06-29 15:09:31