跟进:Java中没有枚举的实例控件 [英] Follow up: instance control in Java without enum
问题描述
这是这个问题。这个解决方案是否不漏水?
This is a follow up to this question. Is this solution watertight?
public final class Thing implements Serializable {
private static final long serialVersionUID = 1L;
private static final Thing[] instances = new Thing[2];
private static int nextOrdinal = 0;
public static final Thing instance0 = new Thing("whatever0");
public static final Thing instance1 = new Thing("whatever1");
private transient final String someState;
public String someMethod() {return someState;}
private final int ordinal;
private Thing(String someState) {
this.someState = someState;
this.ordinal = nextOrdinal++;
instances[this.ordinal] = this;
}
private Object readResolve() throws ObjectStreamException {
return instances[this.ordinal];
}
}
推荐答案
此解决方案是否具有防水功能?
Is this solution watertight?
否。 (虽然它可能是足够的,取决于代码的使用方式和位置。)
No. (Though it might be adequate, depending on how and where the code is used.)
在项目77中:对于实例控制,首选枚举类型为readResolve ( Effective Java,2nd ed ),Bloch演示了攻击者如何拥有像你这样的类会返回任何值。攻击依赖于手工制作的字节输入,并且能够在目标上运行代码(因此,如果在沙盒环境中使用,某些RMI情况等,则代码可能存在安全风险)。我不知道这是否是唯一的攻击 - 它是唯一提到的攻击。解决方案是声明所有字段是瞬态的,但是你有如何存储值的问题。
In Item 77: For instance control, prefer enum types to readResolve (Effective Java, 2nd ed), Bloch demonstrates how an attacker could have a class like yours return any value. The attack relies on hand-crafted byte input and being able to run code on the target (so your code might be a security risk if used in sand-boxed environments, some RMI cases, etc.). I do not know if that is the only attack - it is the only one mentioned. The solution is to declare all fields transient, but then you have the issue of how to store the value.
你可以使用序列化代理模式(书中的第78项 - 每个读过它的Java程序员都推荐它的原因。)
You may be able to get round these problems using the serialization proxy pattern (Item 78 in the book - there's a reason every Java programmer who's read it recommends it).
public final class Thing implements Serializable {
private static final long serialVersionUID = 1L;
private static final Thing[] INSTANCES = new Thing[2];
private static int NEXT_ORDINAL = 0;
public static final Thing INSTANCE0 = new Thing(
"whatever0");
public static final Thing INSTANCE1 = new Thing(
"whatever1");
private transient final String someState;
public String someMethod() {
return someState;
}
private final int ordinal;
private Thing(String someState) {
this.someState = someState;
ordinal = NEXT_ORDINAL++;
INSTANCES[ordinal] = this;
}
private Object writeReplace() {
return new ThingProxy(this);
}
private void readObject(ObjectInputStream stream)
throws InvalidObjectException {
throw new InvalidObjectException("Proxy required");
}
private static class ThingProxy implements Serializable {
private static final long serialVersionUID = 1L;
private final int ordinal;
private ThingProxy(Thing t) {
ordinal = t.ordinal;
}
private Object readResolve()
throws ObjectStreamException {
return INSTANCES[ordinal];
}
}
}
虽然,与复制任何与互联网相关的安全性一样,但需要注意。我绝不是专家。
Though, as with copying anything security related from the internet, caveat emptor. I am by no means an expert.
这篇关于跟进:Java中没有枚举的实例控件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!