用其他方式破解单身人士

时间:2012-07-25 16:58:54

标签: java

我正在研究单身人士,我已经开发了一个非常基本的单身人士课程。

public class SingletonObject {
    private static SingletonObject ref;
    private SingletonObject () //private constructor
    { }

    public  static synchronized   SingletonObject getSingletonObject()
    {
        if (ref == null)
            ref = new SingletonObject();
                return ref;
        }


    public Object clone() throws CloneNotSupportedException
    {throw new CloneNotSupportedException ();
    }   
}

现在,下面是我破解单身人士的一种方式..

public class CrackingSingleton {

     public static void main(String[] args) throws ClassNotFoundException,
       IllegalArgumentException, SecurityException,
       InstantiationException, IllegalAccessException,
       InvocationTargetException {

        //First statement retrieves the Constructor object for private constructor of SimpleSingleton class.
        Constructor pvtConstructor = Class.forName("CrackingSingleton.SingletonObject").getDeclaredConstructors()[0];
        //Since the constructor retrieved is a private one, we need to set its accessibility to true.
        pvtConstructor.setAccessible(true);
        //Last statement invokes the private constructor and create a new instance of SimpleSingleton class.
         SingletonObject  notSingleton1 = ( SingletonObject) pvtConstructor.newInstance(null);
         System.out.println(notSingleton1.hashCode());
         System.out.println("notSingleton1 --->"+notSingleton1.toString());
         SingletonObject  notSingleton2 = ( SingletonObject) pvtConstructor.newInstance(null);
         System.out.println("notSingleton2 --->"+notSingleton2.hashCode());
         System.out.println(notSingleton2.toString());
    }
}

请告知其他单身人士破裂的方法.. !!

6 个答案:

答案 0 :(得分:5)

我能想到的三种方式是:

序列化

如果您的单例类是可序列化的,那么您可以序列化它的一个实例,然后反序列化它并获得该类的第二个对象。

您可以通过实施readResolve方法来避免这种情况。

public class Singleton implements Serializable {
   private static final Singleton INSTANCE = new Singleton();

   public static Singleton getInstance(){
       return INSTANCE;
   }

   public Object readResolve() throws ObjectStreamException {
        return INSTANCE; //ensure singleton is returned upon deserialization.
   }
}

类加载

同一个类可以由两个不同的类加载器加载,因此,您可以通过在由两个不同的类加载器加载的类中调用其getInstance方法来创建单个类的两个实例。这种方法可以工作,而不必诉诸于违反私有构造函数

ClassLoader cl1 = new URLClassLoader(new URL[]{"singleton.jar"}, null);
ClassLoader cl2 = new URLClassLoader(new URL[]{"singleton.jar"}, null);
Class<?> singClass1 = cl1.loadClass("hacking.Singleton");
Class<?> singClass2 = cl2.loadClass("hacking.Singleton");
//...
Method getInstance1 = singClass1.getDeclaredMethod("getInstance", ...);
Method getInstance2 = singClass2.getDeclaredMethod("getInstance", ...);
//...
Object singleton1 = getInstance1.invoke(null);
Object singleton2 = getInstance2.invoke(null);

反射

正如您已经指出的那样,通过反射,您可以创建该类的两个实例。我认为前面的例子只是同一种方法的一种变体。但我相信你可以使用SecurityManager阻止这两者发生。

System.setSecurityManager(new SecurityManager());

答案 1 :(得分:2)

如果你有两个类加载器,你将能够从每个类加载器创建一个单例。

文件"When is a singleton not a singleton"也值得一读。

答案 2 :(得分:1)

我的回答是:

为什么重要?

如果您正在尝试设计安全,无法破解的代码,那么Singleton就不是解决方案。它旨在强制普通开发人员使用它的系统实例。所有这些绕过它的方法都需要大量的额外工作,而有些人不会仅仅使用不同的类实例。

答案 3 :(得分:1)

在某些情况下,Singleton的行为并不像。

1.如果单例类被垃圾收集破坏,则重新加载。
2.多个虚拟机中不止一个单身人士 3.不同类型装载机同时装载的单个单人 具有经过序列化和反序列化的Singleton对象的4Copies

答案 4 :(得分:0)

通过反射,设置ref = null。通过将其重新指定为null,将在下次调用getSingletonObject时再次触发延迟构造单例的逻辑。

答案 5 :(得分:0)

您可以使用字节码工程库公开单例构造函数。

此外,在一些较旧的Java版本中(这曾经在1.3中工作),您可以简单地创建一个具有相同名称的类,使用公共构造函数和针对该类的编译。在运行时,这允许您创建真实类的实例(此漏洞已在以后的JRE版本的字节码验证中得到修复)。