3

Is the following code resistant to both Serialization and Reflection Attacks?

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

  private Example(){}

  public static Example getInstance(){
    return instance;
  }

}
John Kane
  • 4,383
  • 1
  • 24
  • 42
  • 1
    One could extend your class, override getInstance() and return something else... Solution to this issue is to make class and getInstance() final. – Jérôme Verstrynge Apr 20 '11 at 20:01
  • 4
    @JVerstry: getInstance is static, and thus can't be overridden. The class is implicitely final, since it's constructor is private : no subclass of Example could ever be created. static methods are implicitely final, since they can't be overridden. Declaring it final would have no effect at all. – JB Nizet Apr 20 '11 at 20:10
  • @JB Nizet Yes, it can. Just try. The fact that the constructor is private does not prevent this. Static methods are NOT implicitly final. Declaring it final DOES have an effect. – Jérôme Verstrynge Apr 20 '11 at 20:20
  • @JVerstry: read the JLS. static methods can't be overridden. They can be hidden (and can't if the method is marked final), but hiding is very different from overriding. And classes with only private constructor are implicitly final. Just try to make a subclass of Example. – JB Nizet Apr 20 '11 at 20:44
  • Oops, I did implement an example but forgot the private constructor. I stand corrected. But if I remove the private constructor, I can override the static method. – Jérôme Verstrynge Apr 20 '11 at 20:47
  • JB, a subclass is possible if it's nested within `Example` – irreputable Apr 20 '11 at 20:47
  • @irreputable: yes, of course, but it still means it's not possible to create another Example instance without reflection and without altering the Example class itself. – JB Nizet Apr 20 '11 at 20:58
  • 2
    @JVerstry. No, you can't override the static method. You can hide it, which is very different. Read http://download.oracle.com/javase/tutorial/java/IandI/override.html to understand the difference. – JB Nizet Apr 20 '11 at 21:00
  • @JB Nizet The class can be subclassed in bytecode, although you can't create an instance of it (well, perhaps you could in JDK5/J2SE 1.4). – Tom Hawtin - tackline Apr 20 '11 at 22:18

5 Answers5

8

To quote Joshua Bloch,

As of release 1.5, there is a third approach to implementing singletons. Simply make an enum type with one element:

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

     public void leaveTheBuilding(){...} 
 }

This approach is functionally equivalent to the public field approach, except that it is more concise, provides the serialization machinery for free, and provides an ironclad guarantee against multiple instantiation, even in the face of sophisticated serialization or reflection attacks.

Reference.

EDIT:

If you want to know why, according to Joshua Bloch,

To maintain the singleton guarantee, you have to declare all instance fields transient and provide a readResolve method. Otherwise, each time a serialized instance is deserialized, a new instance will be created ...

mre
  • 43,520
  • 33
  • 120
  • 170
  • 2
    Bloch is making up some nonsense to sell his "invention". Singletons are heavy objects, nobody would serialize them. And if someone really wants to serialize a singleton, the snapshot state of the singleton must be saved, and restored when deserialized. Enum doesn't do that. Using enum for singleton is simply an abuse of its capabilities. Among many reasons, enums are supposed to be simple immutable objects; singletons are mostly mutables. – irreputable Apr 20 '11 at 20:32
  • There are errors in Effective Java's coverage of serialisation (including the quoted text). Don't do mutable statics, including dressed up as singletons. Immutable "singletons" are fine and unexceptional. – Tom Hawtin - tackline Apr 20 '11 at 22:16
  • @tom-hawtin-tackline we can't avoid mutable global states. well we can - superfacially. and a stateless/immutable singleton doesn't usually care if there are clones. – irreputable Apr 21 '11 at 00:08
  • @TomHawtin-tackline - I know it's a year since your post, but what errors in "Effective Java" are you referring to? Serious, honest question. – luis.espinal Apr 26 '12 at 21:48
  • @luis.espinal In the piece quoted in the "edit" to this answer, you can still get a back reference to the "singleton". (Enums "work", but still, mutable globals are an outrageously bad idea, even dressed up in pointless boilerplate.) – Tom Hawtin - tackline Apr 27 '12 at 06:46
  • @TomHawtin-tackline - sorry I still don't get it. Are we referring to *"errors"* as in *something that is not true as per the JLS or JVM specs* or *"errors"* as in something that is considered bad practice? Honest question (this very specific to the errors in Bloch's coverage of serialization). – luis.espinal May 02 '12 at 19:31
  • @luis.espinal Errors as in the quoted piece of Effective Java does not agree with either the Java Serialisation specification or `java.io.ObjectInputStream`. – Tom Hawtin - tackline May 02 '12 at 22:33
  • What *is* a reflection attack in this context? Bloch makes a provocative remark about it but doesn't explain? Thanks for info – slashdottir Jan 29 '15 at 21:14
4

No, it is not. There is a better technique.

Try something like this:

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

// In your code:
if ( !Elvis.INSTANCE.isThereOnlyOneElvis() ) {
    System.err.println("Liar !!!");
}
Jérôme Verstrynge
  • 57,710
  • 92
  • 283
  • 453
4

OO design is not meant to prevent attacks, IMHO. It can be useful to prevent inappropriate usage of your classes and bugs due to bad comprehension, irrespect of the contract, incompetence, or programming errors, though.

Since your Example class is not serializable, I would say that serialization is not a problem in this case. Regarding reflection, if someone uses it to create another instance of your singleton, then he's obviously malicious IMO, and risks shooting himself in the foot anyway.

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • 1
    I see what you are trying to say, but I would disagree a bit. An OO (or procedural, modular, FP) design is meant to describe (within the paradigm of choice) a solution design (no pun intended) for a series of requirements. If one of the requirements involves attack prevention (or security features in general terms), then the underlying solution design (and ergo the OO design) will have to meet that requirement in order for it to be valid. – luis.espinal Apr 26 '12 at 21:57
2

As far as reflection is concerned , the singleton in context is NOT reflection proof. U can use setAccssible(true) to get hold of private constructor and instantiate the singleton. You can get more details about this thing at - http://technonstop.com/java-singleton-reflection-and-lazy-initialization

Naweed Chougle
  • 500
  • 10
  • 31
Vishal
  • 21
  • 1
-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);
        }

    }
}
Suman Boorla
  • 89
  • 1
  • 2
  • There is absolutely no answer to the actual question asked here. Please carefully read the question and help the person with what they are having trouble with specifically; don't just dump code that you think solves the problem. – Andrew Barber Aug 25 '14 at 17:24