单例模式克隆攻击以及防御
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
|
* @date 2018-09-24 15:38
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class HungrySingletonReflectImprove implements Serializable {
|
public class HungrySingletonReflectImprove implements Serializable, Cloneable {
|
||||||
|
|
||||||
private static final HungrySingletonReflectImprove HUNGRYSINGLETON;
|
private static final HungrySingletonReflectImprove HUNGRYSINGLETON;
|
||||||
|
|
||||||
@@ -29,6 +29,11 @@ public class HungrySingletonReflectImprove implements Serializable {
|
|||||||
log.debug(HungrySingletonReflectImprove.class.getSimpleName() + "构造器实例化");
|
log.debug(HungrySingletonReflectImprove.class.getSimpleName() + "构造器实例化");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Object clone() throws CloneNotSupportedException {
|
||||||
|
return super.clone();
|
||||||
|
}
|
||||||
|
|
||||||
public static HungrySingletonReflectImprove getInstance() {
|
public static HungrySingletonReflectImprove getInstance() {
|
||||||
return HUNGRYSINGLETON;
|
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