034-安全开发-JavaEE应用&反射机制&攻击链&类对象&成员变量方法&构造方法

034-安全开发-JavaEE应用&反射机制&攻击链&类对象&成员变量方法&构造方法

Untitled

#知识点:

1、JavaEE-反射机制-开发和安全应用场景
2、JavaEE-反射机制-类&成员变量&方法&构造方法操作
3、JavaEE-反射机制-安全应用&反射执行&反序列化链相关

演示案例:

➢Java-反射-Class对象类获取
➢Java-反射-Field成员变量类获取
➢Java-反射-Method成员方法类获取
➢Java-反射-Constructor构造方法类获取
➢Java-反射-不安全命令执行&反序列化链

Untitled

Untitled

Untitled

Untitled

#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);

Untitled

#Java-反射-Field成员变量类获取

Untitled

1.获取公共的成员变量:Field[] fields1 = aClass.**getFields()**;

Untitled

2.获取所有的成员变量:Field[] fields = aClass.getDeclaredFields();

Untitled

3.获取单个的公共成员变量:Field name = aClass.getField("name");

Untitled

4.获取单个的成员变量:Field gender = aClass.getDeclaredField("gender");

Untitled

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);**赋值

Untitled

#Java-反射-Constructor构造方法类获取

Untitled

1.获取公共的构造方法

Untitled

2.获取所有的构造方法

Untitled

3.获取单个的公共的构造方法

Untitled

4.获取单个的构造方法

Untitled

5.对构造方法进行操作(两个参数string,int),setAccessible(true)临时开启对私有的访问,newInstance 使用构造方法创建对象,传递参数;

newInstance 方法:

  • newInstance 方法是 java.lang.reflect.Constructor 类的一个方法,用于创建新的类实例。
  • 它通过调用类的构造方法来实例化对象。
  • newInstance 方法通常用于动态创建对象,尤其是在反射时,允许在运行时通过 Constructor 对象调用类的构造方法。

setAccessible(true) 方法:

  • setAccessible 方法是 java.lang.reflect.AccessibleObject 类的一个方法,用于启用或禁用 Java 语言访问检查。
  • setAccessible(true) 被调用时,表示反射对象在使用时取消了访问权限检查,可以访问类的私有成员。
  • 这通常用于访问那些受到访问控制限制的类的私有成员(字段、方法、构造方法等)。

Untitled

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成员方法类获取

Untitled

1.获取包括继承公共成员方法

Untitled

2.获取不包括继承所有成员方法

Untitled

3.获取单个的成员方法

public Method getMethod(String name, Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException
  • name:要获取的方法的名称
  • parameterTypes:一个可变参数,用于表示方法的参数类型。

返回值:

  • 返回一个 Method 对象,该对象反映由该 Class 对象表示的类或接口的指定公共方法。

Untitled

4.对成员方法进行执行

  1. User u = new User();: 创建一个 User 对象,即实例化 User 类。
  2. Method users = aClass.getDeclaredMethod("users", String.class, String.class);: 通过反射获取 User 类中名为 “users” 的方法,该方法接受两个参数,类型分别为 StringString
  3. users.invoke(u, "xiaodigay", "gay1");: 使用 invoke 方法调用 User 对象的 users 方法,传递参数 “xiaodigay” 和 “gay1”。这行代码相当于调用 u.users("xiaodigay", "gay1")

Untitled

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”);

Untitled

反射:如果是第三方的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);
    }
    
  • 通过查询找到对应需要的成员方法

  • 根据成员方法的名称和参数,分别对应获取所需成员方法

  • 通过使用获取的方法依次调用执行即可

Untitled

Untitled

// 获取名为 "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

  • 29
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值