单例模式克隆攻击以及防御

This commit is contained in:
2018-09-25 22:52:37 +08:00
parent e4ce7c3744
commit 02e0e79bdf
3 changed files with 112 additions and 1 deletions

View File

@@ -0,0 +1,52 @@
package top.fjy8018.designpattern.pattern.creational.singleton;
import lombok.extern.slf4j.Slf4j;
import java.io.Serializable;
/**
* 单例模式:饿汉式
* 克隆攻击改进
* 要么不要实现克隆接口,要么不要调用父类的克隆实现,转而自己实现克隆方法
*
* @author F嘉阳
* @date 2018-09-24 15:38
*/
@Slf4j
public class HungrySingletonCloneableImprove implements Serializable, Cloneable {
private static final HungrySingletonCloneableImprove HUNGRYSINGLETON;
static {
log.debug(HungrySingletonCloneableImprove.class.getSimpleName() + "静态块实例化");
HUNGRYSINGLETON = new HungrySingletonCloneableImprove();
}
private HungrySingletonCloneableImprove() {
if (HUNGRYSINGLETON != null) {
throw new RuntimeException("单例模式禁止反射调用");
}
log.debug(HungrySingletonCloneableImprove.class.getSimpleName() + "构造器实例化");
}
public static HungrySingletonCloneableImprove getInstance() {
return HUNGRYSINGLETON;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return HUNGRYSINGLETON;
}
/**
* 解决序列化攻击问题
*
* @return
*/
private Object readResolve() {
log.debug("序列化获取对象");
return HUNGRYSINGLETON;
}
}

View File

@@ -13,7 +13,7 @@ import java.io.Serializable;
* @date 2018-09-24 15:38
*/
@Slf4j
public class HungrySingletonReflectImprove implements Serializable {
public class HungrySingletonReflectImprove implements Serializable, Cloneable {
private static final HungrySingletonReflectImprove HUNGRYSINGLETON;
@@ -29,6 +29,11 @@ public class HungrySingletonReflectImprove implements Serializable {
log.debug(HungrySingletonReflectImprove.class.getSimpleName() + "构造器实例化");
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
public static HungrySingletonReflectImprove getInstance() {
return HUNGRYSINGLETON;
}

View File

@@ -0,0 +1,54 @@
package top.fjy8018.designpattern.pattern.creational.singleton;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import java.lang.reflect.Method;
/**
* 单例模式克隆攻击
*
* @author F嘉阳
* @date 2018-09-25 22:40
*/
@Slf4j
class SingletonCloneAttack {
/**
* 改进前
*/
@Test
void before() throws Exception {
// 正常方式获取单例
HungrySingletonReflectImprove instance = HungrySingletonReflectImprove.getInstance();
Method method = instance.getClass().getDeclaredMethod("clone");
// 由于原本的访问权限为protect故要改变访问权限
method.setAccessible(true);
// 克隆实例
HungrySingletonReflectImprove instance2 = (HungrySingletonReflectImprove) method.invoke(instance);
// 验证
log.info(Integer.toHexString(instance.hashCode()));
log.info(Integer.toHexString(instance2.hashCode()));
// 返回false克隆攻击成功
log.info(String.valueOf(instance == instance2));
}
/**
* 改进后
*/
@Test
void after() throws Exception {
// 正常方式获取单例
HungrySingletonCloneableImprove instance = HungrySingletonCloneableImprove.getInstance();
Method method = instance.getClass().getDeclaredMethod("clone");
// 由于原本的访问权限为protect故要改变访问权限
method.setAccessible(true);
// 克隆实例
HungrySingletonCloneableImprove instance2 = (HungrySingletonCloneableImprove) method.invoke(instance);
// 验证
log.info(Integer.toHexString(instance.hashCode()));
log.info(Integer.toHexString(instance2.hashCode()));
// 返回false克隆攻击成功
log.info(String.valueOf(instance == instance2));
}
}