Java:为什么不将clone()用于防御性复制?

时间:2015-04-09 02:45:39

标签: java effective-java

在Effective Java(第7章)中,它说

  

另请注意,我们没有使用Date的克隆方法来制作防御性副本。因为Date是非最终的,所以不能保证clone方法返回一个类为java.util.Date的对象:它可能返回一个专门为恶意恶作剧设计的不可信子类的实例。例如,这样的子类可以在创建时记录对私有静态列表中每个实例的引用,并允许攻击者访问该列表。这将使攻击者在所有实例中自由统治。要防止此类攻击,请不要使用克隆方法制作类型可由不信任方进行子类化的参数的防御副本。

我不太明白它的解释。为什么clone()不返回Date对象?该实例如何成为不受信任的子类?

3 个答案:

答案 0 :(得分:3)

考虑以下代码:

public class MaliciousDate extends Date { /** malicious code here **/ }

public class SomeClass {
    public static void main(String[] args) {
        MaliciousDate someDate = new MaliciousDate();
        Date copyOfMaliciousDate = someDate;
        Date anotherDate = copyOfMaliciousDate.clone();
    }
}

由于copyOfMaliciousDate类型为Date,您可以致电clone(),它会返回Date个对象,但会在clone上调用copyOfMaliciousDate执行MaliciousDate类中编写的代码,因为copyOfMaliciousDate中存储的实例MaliciousDate

答案 1 :(得分:2)

出于多种原因,

clone()被广泛认为是一次失败的实验。在这种情况下,传入Date的人可能已经传递了EvilDate extends Date clone()方法偷偷地返回了一个仍然可由他人修改的副本。

答案 2 :(得分:0)

我还没有阅读过您引用的书,但是该段的理由不充分,也无法抵御任何形式的攻击。<​​/ p>

引文中提到,具有将代码加载到程序中的能力的攻击者可能会使用恶意方法提交Date子类,例如,从Date返回clone的子类。

但这只是具有加载代码能力的攻击者可能造成伤害的次要方式。他们还可以:

  • 使用反射来获取对几乎所有标记为私有的内容的读写访问权限
  • 缺少类加载器来加载自己的类版本,
  • 致电System.exit()停止程序,然后
  • 执行程序可以做的任何事情,例如生成其他程序或访问文件。

如果攻击者在您的进程中运行代码,则游戏结束并且您的进程受到威胁,而这个愚蠢的后卫将无济于事。

从设计的角度来看,也许您认为克隆是不好的,这很好,但是请不要假装不使用它会保护您免受某种安全威胁,因为它不会。