单例模式克隆攻击以及防御
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user