Java readResolve()错误?

Java readResolve()错误?,java,serialization,Java,Serialization,说明readResolve仅在所有字段都是瞬态的情况下工作。 这不是一只虫子吗?为什么Java创建者会做这样的事情 -更新 对不起,我是说,请看幻灯片30。我想你误解了乔希·布洛赫。从java: 用于序列化和外部化 类,readResolve方法允许 用于替换/解析对象的类 在流被读取之前读取流 返回给打电话的人。通过 实现readResolve方法时 类可以直接控制类型 以及其自身实例的实例 被反序列化 正如你所看到的,这里与你的陈述没有任何相似之处 据我所知,readResolve最典型的用

说明readResolve仅在所有字段都是瞬态的情况下工作。 这不是一只虫子吗?为什么Java创建者会做这样的事情

-更新


对不起,我是说,请看幻灯片30。

我想你误解了乔希·布洛赫。从java:

用于序列化和外部化 类,readResolve方法允许 用于替换/解析对象的类 在流被读取之前读取流 返回给打电话的人。通过 实现readResolve方法时 类可以直接控制类型 以及其自身实例的实例 被反序列化

正如你所看到的,这里与你的陈述没有任何相似之处


据我所知,readResolve最典型的用例之一是当您读取序列化的singleton或任何您不想为其创建新实例的对象时,如手动实现的枚举,即不使用enum关键字。在readResolve中,如果字段存在,您可以读取字段,并决定应该像往常一样返回哪些已创建的对象单例,而不是创建新实例。

为完整起见,幻灯片29为:

第77项:突击测验:这个班是单身吗? 幻灯片30是:

回答:不幸的是没有 第一版夸大了readResolve的威力 >Elvis有一个非瞬态字段 favoriteSongs>巧妙地 精心设计的攻击可以保存对的引用 反序列化 猫王的例子 此字段已反序列化

有关第77项的详细信息,请参见Elvistealer >readResolve仅在以下情况下工作: 所有磁场都是瞬态的

项目77是:

第77项:对于实例控件,首选枚举类型而不是readResolve

如果猫王的职业是 实现可序列化,如下所示 readResolve方法足以 保证singleton属性:

// readResolve for instance control - you can do better!
private Object readResolve() {
  // Return the one true Elvis and let the garbage collector
  // take care of the Elvis impersonator.
  return INSTANCE;
}
此方法忽略反序列化的 对象,返回 Elvis实例,该实例是在 该类已初始化。因此 猫王的序列化形式 实例不需要包含任何实数 数据所有实例字段都应为 宣布暂时的。事实上,如果你 例如,依赖readResolve 控件的所有实例字段 对象引用类型必须是 宣布暂时的。否则就是 坚定的攻击者可能 保护对反序列化对象的引用 对象的readResolve方法之前 正在运行,使用的技术是 模糊地类似于可变周期 攻击第76项

攻击有点复杂,但是 基本思想很简单。如果 singleton包含一个非transient 对象引用字段中的内容 此字段的值将被反序列化 在singleton的readResolve之前 方法正在运行。这就允许仔细检查 精心编制的流“窃取”引用 到最初反序列化的 当时单身汉的内容 对象引用字段是 反序列化

这不是只有在所有字段都是瞬态的情况下才工作,而是只有在所有对象引用都是瞬态的情况下才安全。您引用的幻灯片进一步指出,任何字段都是非瞬态的,攻击者可以获取对反序列化对象的引用


至于原因:可以说Josh Bloch对singleton使用readResolve是无意中使用了API,这是创作者在制作时没有想到的。你也可以说这只是一个无法预料的结果。然而,我并不认为这是一个故意的弱点。

在使用readResolve时,目标JVM中的单例行为无论如何是违反的,因为readResolve将返回对JVM中已经存在的实例的引用

但是readObject将在readResolve调用之前被调用,而Singleton类的另一个对象将在反序列化期间由JVM使用反射创建。
无论如何,这个对象可能会被垃圾收集,但目标JVM暂时有两个相同类型的实例,这可能会使其无法成为单例

我怀疑这本书是否这样说,因为这不是真的。你能引用这本书,而不是解释它吗?正如我们现在看到的,它没有这样说。它说“如果您依赖readResolve作为实例控件,则所有具有对象引用类型的实例字段都必须声明为瞬态。”注意“如果”部分…我会发布错误的链接,请查看我的更新。@Tom Brito:我看到了您的更新。无可奉告,我从未做过如此棘手的事情。如果你有ElvisStealer类的源代码,发布它们,这很有趣。不,只是前面的幻灯片。是的,这一段解释得更好,现在看起来像是一个程序错误,而不是前Sun的。我认为我看到的错误更改的幻灯片只有在以下情况下才有效。@cletus:Josh Block说“攻击者”是指谁?当有人想/需要在我的程序中创建第二个单例时,我就不理解这种情况。@Roman:这里的攻击者有点用词不当,因为它要求代码在同一个VM中运行,而在代码级别上实际上没有这样的代码
这是代码安全性的问题,但它关系到为Google应用程序引擎实现Java的子集,这是在VM中运行的代码,可以被视为恶意代码。所以,如果他们使用readResolve来确保GAE上的一个单例,它将很容易受到攻击。如果所有字段都是瞬态的,那么它就不是真正安全的。避免单身。甚至避免使敏感类可序列化。
// readResolve for instance control - you can do better!
private Object readResolve() {
  // Return the one true Elvis and let the garbage collector
  // take care of the Elvis impersonator.
  return INSTANCE;
}