Java反射机制指的是程序在运行时能够获取自身的信息;它能动态截获或改写程序的行为。
1. 单例模式漏洞
/**
* 懒汉式单例模式
*/
public class Singleton {
private static Singleton instance = null;
private Singleton() {
}
public static synchronized Singleton getInstance() {
if( instance == null ){
instance = new Singleton();
}
return instance;
}
}
常规情况下,只能通过 getInstance() 创建实例;但是通过反射可以直接调用private方法创建实例。
/**
* 单例反射攻击
*/
public static void singletonTest() throws Exception {
Class<Singleton> clazz = (Class<Singleton>)Class.forName( "com.sun.Singleton" );
Constructor<Singleton> constructor = clazz.getDeclaredContructor( null );
constructor.setAccessible( true ); // 允许访问私有属性,跳过权限检查
// 成功创建多个实例
Singleton s1 = constructor.newInstance();
Singleton s2 = constructor.newInstance();
}
解决方案:在无参构造函数中再次检测instance是否存在。
2. 泛型漏洞
面试题:
给一个ArrayList<Integer>的一个对象,要在这个集合中添加一个字符串数据,如何实现呢?
大家都知道,泛型约束了集合的数据类型,添加非Integer数据会引起编译错误。
/**
* 反射突破泛型检测
*/
public static void addString() throws Exception {
List<Integer> list = new ArrayList<Integer>();
list.add( 1 );
// Get class
Class<? extends List> clazz = list.getClass();
// Get add method
Method method = clazz.getMethod( "add", Object.class );
// invoke
Object obj = method.invoke( list, "str1" );
obj = method.invoke( list, "str1" );
obj = method.invoke( list, "str2" );
// print
for( Object i : list ){
System.out.println( "Val: " + i );
}
}
上述代码成功绕开泛型检测,执行结果如下:
Val: 1
Val: str1
Val: str2