avatar

cindahy

A text-focused Halo theme

  • 首页
  • 文章分类
  • 项目
  • 关于
Home java-反序列化基础3——JDK动态代理
文章

java-反序列化基础3——JDK动态代理

Posted 2025-08-12 Updated 2025-08- 15
By Administrator
15~20 min read

代理模式的通用类图

上图中,Subject是一个抽象类或者接口,RealSubject是实现方法类,具体的业务执行,Proxy则是RealSubject的代理,直接和client接触的。

静态代理

以租房为例,首先定义一个租房的接口

public interface IRentHouse{
    void rentHouse();
}

定义租房的实现类

public class RentHouse implements IRentHouse {
    @Override
    public void rentHouse() {
        System.out.println("租了一间房子。。。");
    }
}

再定义一个中介,在中介中传入要租的房子,中介帮你完成租房操作,这就是代理

在中介中也实现了租房的接口

public class IntermediaryProxy implements IRentHouse {

    private IRentHouse rentHouse;

    public IntermediaryProxy(IRentHouse irentHouse){
        rentHouse = irentHouse;
    }

    @Override
    public void rentHouse() {
        System.out.println("交中介费");
        rentHouse.rentHouse();
        System.out.println("中介负责维修管理");
    }
}

在main方法中进行测试

public class Main {

    public static void main(String[] args){
        //定义租房
        IRentHouse rentHouse = new RentHouse();
        //定义中介
        IRentHouse intermediary = new IntermediaryProxy(rentHouse);
        //中介租房
        intermediary.rentHouse();
    }
}

返回信息

交中介费
租了一间房子。。。
中介负责维修管理

总的来说就是一个接口,一个实体实现类,一个代理实现类,一个启动器

静态代理的优缺点

优点:职责清晰,扩展性好,保护真实主题

缺点:代码冗余,维修困难,灵活性差

动态代理

所有的interface类型的变量总是通过某个实例向上转型并赋值给接口类型变量的:

CharSequence cs = new StringBuilder();

那有没有可能不编写实现类,直接在运行期间创建某个interface 的实例呢?

这是可能的,java标准库提供了一种动态代理机制,可以在运行期间动态创建某个interface的实例。

一个简单的动态代理实现如下:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class Main {
    public static void main(String[] args) {
        InvocationHandler handler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println(method);
                if (method.getName().equals("morning")) {
                    System.out.println("Good morning, " + args[0]);
                }
                return null;
            }
        };
        Hello hello = (Hello) Proxy.newProxyInstance(
            Hello.class.getClassLoader(), // 传入ClassLoader
            new Class[] { Hello.class }, // 传入要实现的接口
            handler); // 传入处理调用方法的InvocationHandler
        hello.morning("Bob");
    }
}

interface Hello {
    void morning(String name);
}

//返回结果
// public abstract void org.example.Hello.morning(java.lang.String)
// Good morning, Bob

  • 定义了一个InvocationHandler实例,它负责实现接口的方法调用

  • Object invoke(Object proxy, 方法 method, Object[] args);

  • proxy – 调用该方法的代理实例

  • method-被调用的方法对应的 Method 对象

  • Object[] args-方法调用时传入的参数数组

  • 通过Proxy.newProxyInstance()创建interface实例,它需要3个参数:

  • 使用的ClassLoader,通常就是接口类的ClassLoader;

  • 需要实现的接口数组,至少需要传入一个接口进去;

  • 用来处理接口方法调用的InvocationHandler实例。

  • 将返回的Object强制转型为接口

所以如果用动态代理表示租房过程就是

接口类:

public interface IRentHouse {
    public void add();
    public void delete();
    public void update();
    public void query();

}

实体实现类



public class RentHouse implements IRentHouse {
    @Override
    public void add() {
        System.out.println("增加了一个用户");
    }

    @Override
    public void delete() {
        System.out.println("删除了一个用户");
    }

    @Override
    public void update() {
        System.out.println("更新了一个用户");
    }

    @Override
    public void query() {
        System.out.println("查询了一个用户");
    }
}

代理实现类


import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class IntermediaryProxy implements InvocationHandler {

    IRentHouse rentHouse;
    
    public void setIntermediaryProxy(IRentHouse iRentHouse) {
        this.rentHouse = iRentHouse;
    }

    // 动态生成代理类实例
    public Object getProxy(){
        Object obj = Proxy.newProxyInstance(this.getClass().getClassLoader(), rentHouse.getClass().getInterfaces(), this);
        return obj;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        log(method);
        System.out.println("调用了"+method.getName());
        Object obj=method.invoke(rentHouse,args);
        return obj;
    }
    //业务自定义需求
    public void log(Method method){
        System.out.println("[Info] " + method.getName() + "方法被调用");
    }
}

启动器:


import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class Renttext {

        public static void main(String[] args){

            RentHouse rentHouse = new RentHouse();

            IntermediaryProxy intermediaryProxy=new IntermediaryProxy();
            intermediaryProxy.setIntermediaryProxy((IRentHouse) rentHouse);

            IRentHouse proxy=(IRentHouse) intermediaryProxy.getProxy();

            proxy.add();
            proxy.delete();
            proxy.query();
            proxy.update();

        }
}

运行结果:

在反序列化中动态代理的作用

假设存在一个能漏洞利用的类B.f,比如Runtime.exec

我们将入口类定义为A,最理想的情况是 A[O] -> O.f,那么我们把B传入A就行,但是A中存在O.abc方法,如果O是一个动态代理的话,O里的invoke方法中存在.f的方法,便可以漏洞利用。

相当于

readObject->反序列化自动执行

invoke->有函数调用

java反序列化
java反序列化
License:  CC BY 4.0
Share

Further Reading

Oct 9, 2025

Java反序列化-RMI的几种攻击方式

RMI的基本攻击方式 RMI Client打RMI Registry RMI Client打RMI Server RMI Client 打RMI Registry 与注册中心的交互主要是这句话 Naming.bind("rmi://127.0.0.1:1099/sayHello", new Remo

Sep 28, 2025

Java反序列化-RMI流程分析

概述 官方文档:https://docs.oracle.com/javase/tutorial/rmi/overview.html RMI应用程序通常由两个独立的程序组成,一个服务器和一个客户端。服务端通过绑定这个远程对象类,它可以封装网络操作。客户端层面上只需要传递一个名字,还有地址。RMI提供了

Sep 21, 2025

Shiro反序列化漏洞-Shiro550

环境搭建 tomcat8.5.81 JDK1.7下载地址 https://www.oracle.com/java/technologies/javase/javase7-archive-downloads.html 下载shrio对应的war包 https://github.com/jas502n/

OLDER

Java反序列化基础1

NEWER

模仿星露谷物语的游戏开发实践

Recently Updated

  • 常见安全产品整理(防火墙,WAF,EDR)
  • ELK从入门到实践
  • bp+mumu模拟器app抓包
  • xray漏扫工具
  • Java反序列化-RMI的几种攻击方式

Trending Tags

安全运营 文件上传 php反序列化 xss csrf ssrf xxe sql php 白帽子讲web安全

Contents

©2025 cindahy. Some rights reserved.

Using the Halo theme Chirpy