这个单例能够抵抗序列化和反射攻击吗?

发布于 2024-11-02 10:22:31 字数 214 浏览 0 评论 0原文

以下代码是否能够抵抗序列化和反射攻击?

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

  private Example(){}

  public static Example getInstance(){
    return instance;
  }

}

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;
  }

}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

拥抱影子 2024-11-09 10:22:31

引用约书亚·布洛赫的话:

从 1.5 版本开始,有第三个
实现单例的方法。
只需用一个创建一个枚举类型
元素:

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

     public void leaveTheBuilding(){...} 
 }

这种方法在功能上是
相当于公共领域
方法,只不过它更
简洁,提供序列化
免费机械,并提供
铁证如山,杜绝多重打击
实例化,即使面对
复杂的序列化或
反射攻击

参考

编辑:

如果你想知道为什么,根据 Joshua Bloch 的说法,

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

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 ...

扶醉桌前 2024-11-09 10:22:31

不,事实并非如此。有更好的技术。

尝试这样的事情:

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

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

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 !!!");
}
彡翼 2024-11-09 10:22:31

恕我直言,面向对象设计并不是为了防止攻击。不过,无论合同、不称职或编程错误如何,它都有助于防止由于理解不良而导致类的不当使用和错误。

由于您的示例类不可序列化,因此我想说在这种情况下序列化不是问题。关于反射,如果有人用它来创建你的单例的另一个实例,那么在我看来他显然是恶意的,并且无论如何都有搬起石头砸自己脚的风险。

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.

趁年轻赶紧闹 2024-11-09 10:22:31

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

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

带上头具痛哭 2024-11-09 10:22:31
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);
        }

    }
}
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);
        }

    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文