freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

java安全基础-java反射
2023-01-13 16:22:20
所属地 上海

最近开始学习java安全,发现有很多基础知识需要掌握,如java反射,jndi,rmi,类加载机制等等。本篇文章用来记录java反射的学习,后续会继续其它知识的学习。

反射的基本原理

什么是反射?

反射是java的特性之一。java反射机制可以无视类方法,变量去访问权限修饰符,并且可以调用任何类的任意方法,访问并修改成员变量值。

通俗的说java反射可以在运行时根据传参确定要操作的类是什么,并且可以在运行时获取类的完整构造,并调用对应的方法。

看了上面的解释可能我们会有这样的疑问,通常我们都是new一个对象,为什么要多此一步使用反射创建对象?

1)动态的加载程序,例如动态加载插件,刚开始可能根本就不知道要实例化那个类。很多工厂模式都使用了反射

2)从配置文件读取类名,然后在加载。在各类框架中大量应用。

其实就是提供了一种动态创建对象的方式。

反射的作用

反射的作用主要是下面的几种:

在运行时判断任意一个对象所属的类。

在运行时构造任意一个类的对象。

在运行时判断任意一个类所具有的成员变量和方法。

在运行时调用任意一个对象的方法。

生成动态代理

反射的具体应用

1)在开发过程中使用Eclipse、IDEA等开发工具时,当我们输入一个对象或类并想调用它的属性或方法时,编译器会自动列出它的属性或方法

2)JavaBean和JSP之间的调用也是通过反射实现的

3)反射最重要的用途是开发各种通用框架,如上文中提到的Spring框架以及ORM框架,都是通过反射机制来实现的


Class类

在正式学习反射以前,先来认识一下Class类

Class也是一个java类,保存的是与之对应java类的meta信息,用来描述这个类有哪些成员,有哪些方法等。

Java 源程序(.java 文件)在经过 Java 编译器编译之后就被转换成 Java 字节代码(.class 文件)。类加载器负责读取 Java 字节代码,并转换成 java.lang.Class类的一个实例(Class 对象)。也就是说,在 Java 中,每个 java 类都有一个相应的 Class 对象,用于表示这个 java 类的类型信息。

反射的使用

1.获取class方式

要使用发射必须要先获取类的对象class,获取class对象一般有三种方式。

1)通过class.forName()

2)直接获取

3)使用getClass()方法

如下:

/**
 * 获取class的三种方式
 * Class.forName():参数是一个字符串,字符串为一个完整的类名,完整类名必须带有包名。这种方式是最常用的。
 * s.getClass():类的对象通过getClass()方法可以获取到类的Class。
 * 类.class:类名.class来获取
 * 在使用过程中使用比较多的就是第一种
 * **/
Class clazz1 = Class.forName("java.lang.Runtime");
Class clazz2 = Runtime.getRuntime().getClass();
Class<?> clazz3 = Runtime.class;

2.通过Class实例化类

通过Class实例化类可以通过调用类的无参构造函数或者有参构造函数。为了能够方便的使用,目前一般都要求类中包含无参构造函数。

/**
 * 通过Class实例化类
 * 通过无参构造函数实例化类:clazz1.newInstance()
 *调用有参的构造函数实例化类:clazz1.getConstructors();
 * */

try {
    clazz1.newInstance();
} catch (InstantiationException e) {
    e.printStackTrace();
} catch (IllegalAccessException e) {
    e.printStackTrace();
}

Constructor<?> cons[] = null;
Runtime per = null;
//首先通过getConstructors获取全部的构造方法,然后在进行实例化
cons = clazz1.getConstructors();

3.获取类的方法

获取类的所有方法,一般通过下面的方法

1)getDeclaredMethods方法:返回类或接口声明的所有方法,包括public、protected、private和默认方法,但不包括继承的方法返回类或接口声明的所有方法,包括public、protected、private和默认方法,但不包括继承的方法

2)getMethods方法:返回某个类的所有public方法,包括其继承类的public方法

3)getMethod方法:只能返回一个特定的方法

4)getDeclaredMethod方法:与getMethod方法类似,只能返回一个特定的方法。

Method[] declaredMethods = clazz1.getDeclaredMethods();
System.out.println("通过getDeclaredmehtods方式获取方法");
for(Method m:declaredMethods)
    System.out.println(m);



Method[] methods = clazz1.getMethods();
System.out.println("通过getMethods方式获取方法");
for(Method m:methods)
    System.out.println(m);


Method method=clazz1.getMethod("exec", String.class);
System.out.println("通过getMethods方式获取方法");
System.out.println(method);

Method method1 = clazz1.getDeclaredMethod("exec", String.class);
System.out.println("通过getDeclaredMethod方式获取方法");
System.out.println(method1);

4.获取类的成员变量

1)getDeclaredFields方法:getDeclaredFields方法能够获得类的成员变量数组,包括public、private和proteced,但是不包括父类的申明字段

2)getFields:getFields能够获得某个类的所有的public字段,包括父类中的字段

3)getDeclaredField:该方法与getDeclaredFields的区别是只能获得类的单个成员变量,这里我们仅想获得Student 类中的name 变量

4)getField:与getFields类似,getField方法能够获得某个类特定的public字段,包括父类中的字段

Field[] getDeclaredFields = clazz1.getDeclaredFields();
System.out.println("通过getDeclaredFields方式获取变量");
for(Field m:getDeclaredFields)
    System.out.println(m);



Field[] getFields = clazz1.getFields();
System.out.println("通过getFields方式获取变量");
for(Field m:getFields)
    System.out.println(m);


Field getDeclaredMethod=clazz1.getDeclaredField("currentRuntime");
System.out.println("通过getDeclaredMethod方式获取变量");
System.out.println(getDeclaredMethod);

Field getField = clazz1.getField("currentRuntime");
System.out.println("通过getField方式获取变量");
System.out.println(getField);

5.调用类的方法

通过反射调用类的方法,先通过getMethod获取要调用的方法,然后通过invoke调用。

Method getMethod(String name, Class[] params)

name参数指定方法的名字

params参数指定方法的参数类型


invoke(Object obj, Object args[])

第一个参数必须为要调用的对象

第二个参数为要传入的参数对象


下面为利用反射执行函数的一个例子

java正常执行命令的语句是:Runtime.getRuntime().exec("calc.exe")。通过反射如下:

Method method2 = clazz1.getMethod("exec", String.class);
method2.invoke(Runtime.getRuntime(),"calc.exe");


反射的安全性分析

反射给程序带来了极大的便利性,但是同时也带来的安全威胁,很多的反序列化都用到了反射的知识。如在ysoserial中Transformer命令执行链就是运用的反射的知识。因此,使用发射时要注意避免产生安全问题。



# web安全
本文为 独立观点,未经允许不得转载,授权请联系FreeBuf客服小蜜蜂,微信:freebee2022
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者
文章目录