与安全性一样,重要的是要设置适用的上下文。我们对潜在恶意代码可以访问受攻击的受信任类的情况感兴趣。例如,在浏览器中,不受信任的代码可以访问 Java 插件受信任的库。以前是 RMI 加载远程代码的情况,但现在它已经符合默认安全策略。
可变参数的问题是它们可以在检查有效性和使用它们之间进行更改。这被称为检查时间/使用时间漏洞,TOCTOU(或 TOC2TOU)。在实践中,这可以是两种用途,而不是一种用途,特别是支票。其他看起来不可变但可以子类化的糟糕设计的类(例如java.io.File
)可以被子类化为可变的,作为它们在调用时执行任意代码的能力的一部分。
这里讨论的特定攻击场景是clone
被覆盖以阻止复制尝试的地方。在这种情况下,对 a 的引用static
是无关紧要的(它在finalizer
攻击中很重要,但主要反映了攻击代码很少被设计为干净的)。
class MaliciousDate {
private final List<MaliciousDate> dates;
public MaliciousDate(List<MaliciousDate> dates) {
this.dates = dates;
}
@Override public MaliciousDate clone() {
MalicousDate other = (MalicousDate)super.clone(); // Or new MalicousDate
synchronized (dates) {
dates.add(other);
}
return other; // Or return this;
}
}
修改书中的示例。
public Period(Date start, Date end) {
// Failing defensive copy.
start = (Date)start.clone();
end = (Date)end .clone();
if (start.compareTo(end) > 0)
throw new IllegalArgumentExcpetion();
this.start = start;
this.end = end;
}
然后攻击:
List<MaliciousDate> dates = new ArrayList<>()
Date start = new MaliciousDate(dates);
Date end = new MaliciousDate(dates);
Period p = new Period(start, end);
dates.get(1).setYear(78); // Modifies internals of p!
结论:让你的值类型健壮地不可变。更多信息,请参阅非常棒的 Java 编程语言安全编码指南。