034-安全开发-JavaEE应用&反射机制&攻击链&类对象&成员变量方法&构造方法
#知识点:
1、JavaEE-反射机制-开发和安全应用场景
2、JavaEE-反射机制-类&成员变量&方法&构造方法操作
3、JavaEE-反射机制-安全应用&反射执行&反序列化链相关
演示案例:
➢Java-反射-Class对象类获取
➢Java-反射-Field成员变量类获取
➢Java-反射-Method成员方法类获取
➢Java-反射-Constructor构造方法类获取
➢Java-反射-不安全命令执行&反序列化链
#Java-反射-概念
1、什么是Java反射
参考:https://xz.aliyun.com/t/9117
Java提供了一套反射API,该API由Class类与java.lang.reflect类库组成。
该类库包含了Field、Method、Constructor等类。
对成员变量,成员方法和构造方法的信息进行的编程操作可以理解为反射机制。
2、为什么要用到反射
参考:https://xz.aliyun.com/t/9117
其实从官方定义中就能找到其存在的价值,在运行时获得程序或程序集中每一个类型的成员和成员的信息,从而动态的创建、修改、调用、获取其属性,而不需要事先知道运行的对象是谁。划重点:在运行时而不是编译时。(不改变原有代码逻辑,自行运行的时候动态创建和编译即可)
3、反射机制应用
开发应用场景:
Spring框架的IOC基于反射创建对象和设置依赖属性。
SpringMVC的请求调用对应方法,也是通过反射。
JDBC的Class#forName(String className)方法,也是使用反射。
安全应用场景:
构造利用链,触发命令执行
反序列化中的利用链构造
动态获取或执行任意类中的属性或方法
动态代理的底层原理是反射技术
rmi反序列化也涉及到反射操作
#Java-反射-Class对象类获取
-
创建一个User类,包含成员变量和成员方法,构造方法,便于获取反射所对应需要
public class User { //成员变量 public String name="xiaodi"; public int age = 31; private String gender="man"; protected String job="sec"; //构造方法 public User(){ //System.out.println("无参数"); } public User(String name){ System.out.println("我的名字"+name); } private User(String name,int age){ System.out.println(name); System.out.println(age); } //成员方法 public void userinfo(String name,int age,String gender,String job){ this.job=job; this.age=age; this.name = name; this.gender=gender; } protected void users(String name,String gender){ this.name = name; this.gender=gender; System.out.println("users成员方法:"+name); System.out.println("users成员方法:"+gender); } }
1、根据全限定类名:Class.forName(“全路径类名”)
2、根据类名:类名.class
3、根据对象:对象.getClass()
4、通过类加载器获得Class对象://ClassLoader.getSystemClassLoader().loadClass(“全路径类名”);
ClassLoader clsload = ClassLoader.getSystemClassLoader();
: 获取系统类加载器。这是获取应用程序中所有类的加载器。Class aClass2 = clsload.loadClass("com.example.reflectdemo1.User");
: 使用loadClass
方法加载名为 “com.example.reflectdemo1.User” 的类。这是通过类的全限定名进行加载。
//1、根据全限定类名:Class.forName("全路径类名")
Class aClass = Class.forName("com.example.reflectdemo1.User");
System.out.println(aClass);
//2、根据类名:类名.class
Class userClass = User.class;
System.out.println(userClass);
//3、根据对象:对象.getClass()
User user= new User();
Class aClass1 = user.getClass();
System.out.println(aClass1);
//4、通过类加载器获得Class对象://ClassLoader.getSystemClassLoader().loadClass("全路径类名");
ClassLoader clsload=ClassLoader.getSystemClassLoader();
Class aClass2 = clsload.loadClass("com.example.reflectdemo1.User");
System.out.println(aClass2);
#Java-反射-Field成员变量类获取
1.获取公共的成员变量:Field[] fields1 = aClass.**getFields()**
;
2.获取所有的成员变量:Field[] fields = aClass.getDeclaredFields()
;
3.获取单个的公共成员变量:Field name = aClass.getField("name")
;
4.获取单个的成员变量:Field gender = aClass.getDeclaredField("gender")
;
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
Class aClass = Class.forName("com.example.reflectdemo1.User");
//
for(Field fd:fields1){
System.out.println(fd);
}
//2.获取所有的成员变量
Field[] fields = aClass.getDeclaredFields();
for(Field fd:fields){
System.out.println(fd);
}
//3.获取单个的公共成员变量
Field name = aClass.getField("name");
System.out.println(name);
//4.获取单个的成员变量
Field gender = aClass.getDeclaredField("gender");
System.out.println(gender);
//5.获取公共的成员变量age的值
User u = new User();
Field field=aClass.getField("age");
//取值
**Object a=field.get(u);**
System.out.println(a);
//赋值
**field.set(u,32);**
Object aa=field.get(u);
System.out.println(aa);
}
5.创建user类的对象,通过反射获取名为 “age” 的公共成员变量,并进行**field.get(u)取值和field.set(u,32);**赋值
#Java-反射-Constructor构造方法类获取
1.获取公共的构造方法
2.获取所有的构造方法
3.获取单个的公共的构造方法
4.获取单个的构造方法
5.对构造方法进行操作(两个参数string,int),setAccessible(true)
临时开启对私有的访问,newInstance
使用构造方法创建对象,传递参数;
newInstance
方法:
newInstance
方法是java.lang.reflect.Constructor
类的一个方法,用于创建新的类实例。- 它通过调用类的构造方法来实例化对象。
newInstance
方法通常用于动态创建对象,尤其是在反射时,允许在运行时通过Constructor
对象调用类的构造方法。
setAccessible(true)
方法:
setAccessible
方法是java.lang.reflect.AccessibleObject
类的一个方法,用于启用或禁用 Java 语言访问检查。- 当
setAccessible(true)
被调用时,表示反射对象在使用时取消了访问权限检查,可以访问类的私有成员。 - 这通常用于访问那些受到访问控制限制的类的私有成员(字段、方法、构造方法等)。
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
Class aClass = Class.forName("com.example.reflectdemo1.User");
//1.获取公共的构造方法
Constructor[] constructors1 = aClass.getConstructors();
for (Constructor con1 : constructors1) {
System.out.println(con1);
//2.获取所有的构造方法
Constructor[] constructors = aClass.getDeclaredConstructors();
for (Constructor con : constructors) {
System.out.println(con);
//3.获取单个的公共的构造方法
Constructor constructor = aClass.getConstructor(String.class);
System.out.println(constructor);
//4.获取单个的构造方法
Constructor con3 = aClass.getDeclaredConstructor(String.class, int.class);
System.out.println(con3);
// 5. 获取类中声明的具有两个参数(String和int)的构造方法
Constructor con4 = aClass.getDeclaredConstructor(String.class, int.class);
// 6. 临时开启对私有构造方法的访问权限
con4.setAccessible(true);
// 使用构造方法创建对象,传递参数 "xiaodigaygay" 和 40
User uu = (User) con4.newInstance("xiaodigaygay", 40);
System.out.println(uu);
// 获取类中声明的具有一个参数(String)的构造方法
Constructor con2 = aClass.getConstructor(String.class);
// 使用构造方法创建对象,传递参数 "xiaodigaygay"
con2.newInstance("xiaodigaygay");
}
}
}}
#Java-反射-Method成员方法类获取
1.获取包括继承的公共成员方法
2.获取不包括继承的所有成员方法
3.获取单个的成员方法
public Method getMethod(String name, Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException
name
:要获取的方法的名称。parameterTypes
:一个可变参数,用于表示方法的参数类型。
返回值:
- 返回一个
Method
对象,该对象反映由该Class
对象表示的类或接口的指定公共方法。
4.对成员方法进行执行
User u = new User();
: 创建一个User
对象,即实例化User
类。Method users = aClass.getDeclaredMethod("users", String.class, String.class);
: 通过反射获取User
类中名为 “users” 的方法,该方法接受两个参数,类型分别为String
和String
。users.invoke(u, "xiaodigay", "gay1");
: 使用invoke
方法调用User
对象的users
方法,传递参数 “xiaodigay” 和 “gay1”。这行代码相当于调用u.users("xiaodigay", "gay1")
。
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class aClass = Class.forName("com.example.reflectdemo1.User");
//1.获取包括继承的公共成员方法
Method[] methods = aClass.getMethods();
for(Method me:methods){
System.out.println(me);
}
//2.获取不包括继承的所有成员方法
Method[] methods1 = aClass.getDeclaredMethods();
for(Method me:methods1){
System.out.println(me);
}
//3.获取单个的成员方法
Method users = aClass.getDeclaredMethod("users", String.class,String.class);
System.out.println(users);
//4.对成员方法进行执行
// 创建 User 对象
User u = new User();
// 获取名为 "users" 的方法,该方法接受两个参数(String 和 String)
Method users1 = aClass.getDeclaredMethod("users", String.class, String.class);
// 使用反射调用 User 对象的 users 方法,传递参数 "xiaodigay" 和 "gay1"
users1.invoke(u, "xiaodigay", "gay1");
}
#Java-反射-不安全命令执行&反序列化链构造
1、反射实现-命令执行
原型:java自带包含有的java.lang中有对于本机控制台的调用方法
Runtime.getRuntime().exec(“calc”);
反射:如果是第三方的jar包如何实现
-
首先使用 Class.forName获取 java.lang.Runtime 类
-
通过getMethods获取该类包括继承的公共成员方法,并遍历出来
// 使用 Class.forName 获取 java.lang.Runtime 类 Class aClass = Class.forName("java.lang.Runtime"); // 获取 Runtime 类的所有公共方法 Method[] methods = aClass.getMethods(); // 遍历所有方法并打印输出方法信息 for (Method me : methods) { System.out.println(me); }
-
通过查询找到对应需要的成员方法
-
根据成员方法的名称和参数,分别对应获取所需成员方法
-
通过使用获取的方法依次调用执行即可
// 获取名为 "exec" 的方法,该方法接受一个 String 参数
Method exec = aClass.getMethod("exec", String.class);
// 获取名为 "getRuntime" 的方法,该方法不接受参数
Method getRuntimeMethod = aClass.getMethod("getRuntime");
// 使用反射调用 aClass 对象的 getRuntime 方法,获取 Runtime 对象
Object runtime = getRuntimeMethod.invoke(aClass);
// 使用反射调用 Runtime 对象的 exec 方法,执行系统命令 "calc.exe"
exec.invoke(runtime, "calc.exe");
// 使用 Class.forName 获取 Runtime 类
Class c1 = Class.forName("java.lang.Runtime");
// 获取 Runtime 类的默认构造方法
Constructor m = c1.getDeclaredConstructor();
// 设置构造方法为可访问
m.setAccessible(true);
// 使用反射调用 Runtime 类的 exec 方法,执行系统命令 "calc"
c1.getMethod("exec", String.class).invoke(m.newInstance(), "calc");
2、不安全的反射对象
指应用程序使用具有反射功能的外部输入来选择要使用的类或代码,
可能被攻击者利用而输入或选择不正确的类。绕过身份验证或访问控制检查
参考分析:https://zhuanlan.zhihu.com/p/165273855
利用结合:https://xz.aliyun.com/t/7031?time__1311=n4%2BxnD0GDti%3DLxQTq05%2BbDyGD9lBQKDReOYD