Этот синглтон устойчив к сериализации и отраженным атакам? - PullRequest
3 голосов
/ 20 апреля 2011

Является ли следующий код устойчивым к атакам сериализации и отражений?

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

  private Example(){}

  public static Example getInstance(){
    return instance;
  }

}

Ответы [ 5 ]

8 голосов
/ 20 апреля 2011

По словам Джошуа Блоха,

Начиная с версии 1.5, существует третий подход к реализации синглетонов.Просто создайте тип enum с одним элементом:

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

     public void leaveTheBuilding(){...} 
 }

Этот подход функционально эквивалентен подходу открытого поля, за исключением того, что он более лаконичен, предоставляет механизм сериализации бесплатно и предоставляет железную гарантию от множественных экземпляров, даже перед лицом сложных сериализаций или отражений .

Ссылка .

РЕДАКТИРОВАТЬ:

Если вы хотите узнать почему , согласно Джошуа Блоху,

Чтобы сохранить гарантию на одноразовое использование, вы должны объявить всеПоля экземпляра transient и предоставляют метод readResolve.В противном случае каждый раз, когда сериализованный экземпляр десериализуется, будет создаваться новый экземпляр ...

4 голосов
/ 20 апреля 2011

ОО дизайн не предназначен для предотвращения атак, ИМХО.Однако может быть полезно предотвратить нецелевое использование ваших классов и ошибок из-за плохого понимания, неуважения к контракту, некомпетентности или ошибок программирования.

Поскольку ваш класс Example не сериализуем, я бы сказал, что сериализацияэто не проблема в этом случае.Что касается рефлексии, если кто-то использует ее для создания другого экземпляра вашего синглтона, то он, очевидно, злонамеренный ИМО, и в любом случае рискует выстрелить себе в ногу.

4 голосов
/ 20 апреля 2011

Нет, это не так. Есть лучшая техника.

Попробуйте что-то вроде этого:

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

// In your code:
if ( !Elvis.INSTANCE.isThereOnlyOneElvis() ) {
    System.err.println("Liar !!!");
}
2 голосов
/ 11 ноября 2011

Что касается отражения, то синглтон в контексте НЕ является доказательством отражения. Вы можете использовать setAccssible (true), чтобы получить приватный конструктор и создать экземпляр синглтона. Вы можете получить более подробную информацию об этой вещи на - http://technonstop.com/java-singleton-reflection-and-lazy-initialization

0 голосов
/ 25 августа 2014
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);
        }

    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...