跟进:Java中没有枚举的实例控件 [英] Follow up: instance control in Java without enum

查看:93
本文介绍了跟进:Java中没有枚举的实例控件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是这个问题。这个解决方案是否不漏水?

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆