这个Singleton对序列化和反射攻击都有抵抗力吗?

时间:2011-04-20 19:48:34

标签: java design-patterns concurrency

以下代码是否对序列化和反射攻击都有抵抗力?

public class Example{
  private static Example instance=new Example();

  private Example(){}

  public static Example getInstance(){
    return instance;
  }

}

5 个答案:

答案 0 :(得分:8)

引用约书亚布洛赫的话,

  

从1.5版开始,还有第三个   实施单身人士的方法。   只需制作一个枚举类型   元素:

 // Enum singleton - the preferred approach
 public enum Elvis{
     INSTANCE;

     public void leaveTheBuilding(){...} 
 }
  

这种方法在功能上   相当于公共领域   方法,除了它更多   简洁,提供序列化   机械免费,提供   反对多重的铁定保证   实例化,即使面对   复杂的序列化或   反思攻击

Reference

修改

如果你想知道为什么,Joshua Bloch说,

  

维持单身人士保证,   你必须声明所有实例字段   transient并提供一个   readResolve方法。否则,每个   序列化实例的时间   反序列化,一个新的实例将是   创造了......

答案 1 :(得分:4)

不,不是。有一种更好的技术。

尝试这样的事情:

public enum Elvis {
    INSTANCE;
    public static boolean isThereOnlyOneElvis() {
        return true;
    }
}

// In your code:
if ( !Elvis.INSTANCE.isThereOnlyOneElvis() ) {
    System.err.println("Liar !!!");
}

答案 2 :(得分:4)

OO设计并不意味着防止攻击,恕我直言。但是,由于不理解,不遵守合同,无能或编程错误,防止不恰当地使用你的类和错误会很有用。

由于您的Example类不可序列化,我想在这种情况下序列化不是问题。关于反思,如果有人用它来创建你的单身的另一个实例,那么他显然是恶意的IMO,并且无论如何都有可能在脚下射击自己。

答案 3 :(得分:2)

就反射而言,上下文中的单例不是反射证明。你可以使用setAccssible(true)来获取私有构造函数并实例化单例。您可以在 - 获取有关此事的更多详细信息 -  http://technonstop.com/java-singleton-reflection-and-lazy-initialization

答案 4 :(得分:-1)

package com.eiq.singleton;

import java.io.Serializable;

public class SingleTonDemo implements Cloneable, Serializable {

    // order of declaring variables objCount and SingleTonDemo should be same.
    private static int objCount = 0;
    private static SingleTonDemo obj = new SingleTonDemo();

//this value is not needed, to test whether the object value only, you can remove it, the code will work
    int i = 10;

    private SingleTonDemo() {

        // logic to throw exception if we are trying to create object through reflection.
        if (objCount == 0) {
            synchronized (SingleTonDemo.class) {
                if (objCount == 0)
                    objCount++;
            }
        } else {
            throw new RuntimeException(
                    "Singleton class, Object creation is restricted");
        }

    }

    public static SingleTonDemo getInstance() {
        return obj;
    }

    // To avoid duplication
    @Override
    public Object clone() throws CloneNotSupportedException {
        throw new CloneNotSupportedException(
                "Cannot Duplicate Single Ton Object");
    }

    // To avoid serialization and deserialization problems
    public Object readResolve() {
        return SingleTonDemo.getInstance();
    }

}

In the above program will create only one object in all the cases like serialization, cloning, reflection and factory method etc.

This is the testing code:

package com.eiq.singleton;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;

public class TestSingleTon {

    private static final String FILE_PATH = "E:/suman/singleton.txt";

    public static void main(String[] args) throws Exception {

        System.out
                .println("Creating through factory method of SingleTonDemo.getInstance()");
        SingleTonDemo obj = SingleTonDemo.getInstance();
        System.out.println(obj + "  obj  i=" + obj.i);

        // Serializing the object
        FileOutputStream fos = new FileOutputStream(FILE_PATH);
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(obj);

        System.out.println();
        System.out.println("Object creation through deserialization mechanism");
        // Returns the already created object if we trying to create object
        // through Deserialization mechanism.
        // Deserializing the object first time
        FileInputStream fis1 = new FileInputStream(FILE_PATH);
        ObjectInputStream ois1 = new ObjectInputStream(fis1);
        SingleTonDemo deserializedObj1 = (SingleTonDemo) ois1.readObject();
        System.out.println(deserializedObj1 + "  deserializedObj1  i="
                + deserializedObj1.i);

        // Deserializing the object second time, in both the case returns same
        // object
        FileInputStream fis2 = new FileInputStream(FILE_PATH);
        ObjectInputStream ois2 = new ObjectInputStream(fis2);
        SingleTonDemo deserializedObj2 = (SingleTonDemo) ois2.readObject();
        System.out.println(deserializedObj2 + "  deserializedObj2  i="
                + deserializedObj2.i);

        // throws exception if we duplicate the object
        // SingleTonDemo ob = (SingleTonDemo) obj.clone();

        // Through Reflection
        System.out.println();
        System.out
                .println("=====Throwing Exception if we are trying to create object through Reflection=======");
        Class<SingleTonDemo> rObj = (Class<SingleTonDemo>) Class
                .forName("com.eiq.singleton.SingleTonDemo");
        Constructor<SingleTonDemo>[] constructors = (Constructor<SingleTonDemo>[]) rObj
                .getDeclaredConstructors();

        for (Constructor<SingleTonDemo> constructor : constructors) {
            constructor.setAccessible(true);
            SingleTonDemo reflObj1 = constructor.newInstance();
            System.out.println(reflObj1 + "  reflObj1  i=" + reflObj1.i);
        }

    }
}