Collections.unmodifiableList()仅能防止列表结构修改,无法阻止可变元素内部状态被篡改;真正安全需结构不可变(unmodifiableList)加内容不可变(不可变类或深拷贝)。
用 collections.unmodifiablelist() 封装 arraylist 只能防止**列表结构被修改**(比如 add、remove、clear),但**无法阻止元素自身状态被修改**。如果配置项是可变对象(如自定义 pojo),外部仍可通过引用修改其内部字段——这恰恰是核心配置被“恶意篡改”的常见漏洞点。
明确封装目标:既要防结构修改,也要防内容篡改
真正安全的配置保护需分两层:
-
结构不可变:禁止增删改列表长度和顺序 →
unmodifiableList可胜任; - 内容不可变:确保每个配置对象本身不可被修改 → 必须使用不可变类(immutable class)或深度拷贝(deep copy)。
正确做法:返回不可变列表 + 不可变配置对象
推荐在配置类设计阶段就采用不可变模式:
✅ 示例:定义不可变配置项public final class ConfigItem {
private final String key;
private final int value;
private final List<string> tags;
public ConfigItem(String key, int value, List<string> tags) {
this.key = key;
this.value = value;
// tags 也需封装为不可变副本
this.tags = Collections.unmodifiableList(new ArrayList(tags));
}
// 只提供 getter,不提供 setter
public String getKey() { return key; }
public int getValue() { return value; }
public List<string> getTags() { return tags; } // 返回已不可变的副本
}</string></string></string>
✅ 示例:对外提供安全的配置列表private final List<configitem> internalConfigs = new ArrayList();
// 初始化时填入 ConfigItem 实例(全部不可变)
public List<configitem> getConfigs() {
return Collections.unmodifiableList(internalConfigs);
}</configitem></configitem>
若无法改造原有配置类(如用的是普通 JavaBean)
必须在返回前做**防御性拷贝**,避免暴露原始可变对象:
- 对每个可变对象调用 clone() 或构造新实例(需确保深拷贝);
- 再将拷贝后的对象放入新列表,最后套一层
unmodifiableList; - 注意:不要直接对原列表 unmodifiable 后返回——那只是“假安全”。
比如:return Collections.unmodifiableList(originalList),若originalList.get(0)是可变对象,攻击者仍可originalList.get(0).setValue(999)。
额外加固建议
- 将配置集合声明为
private final,初始化后不再重新赋值; - 避免在配置类中暴露任何 setter 或可变集合的 getter(如返回
ArrayList而非List); - 考虑使用
java.util.ImmutableCollections(Java 10+ 的List.of()、Map.of())创建真正不可变容器; - 敏感配置可配合模块封装(module-info.java 中限制包导出)或 SecurityManager(已弃用,仅作了解)。










