JAVA安全基础(三)-- java动态代理机制
字数 985 2025-08-06 08:35:19

Java动态代理机制深入解析

0x01 前言

Java动态代理机制位于java.lang.reflect.Proxy包中,其本质是通过反射执行invoke方法来动态获取执行方法。与反射机制类似,动态代理也是Java安全研究中的重要组成部分。

0x02 代理模式概念

代理模式是Java中最常用的设计模式之一,其特征是:

  • 代理类与委托类有同样的接口
  • 代理类主要负责为委托类预处理消息、过滤消息、转发消息以及事后处理消息

Java代理机制分为:

  • 静态代理:编译时确定代理关系
  • 动态代理:运行时动态生成代理类

0x03 静态代理示例

接口定义

public interface Rental {
    public void sale();
}

委托类实现

public class Entrust implements Rental {
    @Override
    public void sale() {
        System.out.println("出租房子");
    }
}

代理类实现

public class AgentRental implements Rental {
    private Rental target; // 被代理对象
    
    public AgentRental(Rental target) {
        this.target = target;
    }
    
    @Override
    public void sale() {
        System.out.println("房子出租价位有1k-3k"); // 增加新操作
        target.sale(); // 调用委托类方法
    }
}

静态代理优缺点

优点

  • 不改变委托类源代码即可扩展功能

缺点

  1. 接口变更时,委托类和代理类都需要修改
  2. 代理多个类时代理类数量会膨胀
  3. 不易维护和管理

0x04 Java动态代理核心组件

1. InvocationHandler接口

  • 由代理对象调用处理器实现的接口
  • 定义invoke()方法
  • 代理对象上的方法调用会自动转发到InvocationHandler.invoke()

2. Proxy类

提供四个静态方法:

  1. getProxyClass(ClassLoader,Class<?>...):获取指定类加载器和接口的动态代理类
  2. newProxyInstance(ClassLoader,Class<?>[],InvocationHandler):创建代理实例
  3. isProxyClass(Class<?>):判断类是否为动态代理类
  4. getInvocationHandler(Object):获取代理类关联的调用处理器

0x05 动态代理实现过程

1. 创建调用处理器

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

public class TestAgent implements InvocationHandler {
    private Object target; // 委托类对象
    
    public TestAgent(Object target) {
        this.target = target;
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("房子出租价位有1k-3k"); // 自定义逻辑
        return method.invoke(target, args); // 调用委托类方法
    }
}

2. 创建代理对象

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

public class test {
    public static void main(String[] args) {
        // 获取委托类实例
        Entrust testEntrust = new Entrust();
        
        // 获取ClassLoader
        ClassLoader classLoader = testEntrust.getClass().getClassLoader();
        
        // 获取所有接口
        Class[] interfaces = testEntrust.getClass().getInterfaces();
        
        // 获取调用处理器
        InvocationHandler invocationHandler = new TestAgent(testEntrust);
        
        // 保存生成的代理类字节码(调试用)
        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
        
        // 创建代理对象
        Rental proxy = (Rental) Proxy.newProxyInstance(
            classLoader, 
            interfaces, 
            invocationHandler
        );
        
        // 调用代理方法
        proxy.sale();
    }
}

3. 生成的代理类分析

生成的$Proxy0.class关键部分:

public final class $Proxy0 extends Proxy implements Rental {
    private static Method m3; // sale方法
    
    static {
        try {
            m3 = Class.forName("com.DynamicProxy.Rental").getMethod("sale");
        } catch(Exception e) {
            // 异常处理
        }
    }
    
    public final void sale() {
        try {
            super.h.invoke(this, m3, (Object[])null); // 转发到InvocationHandler
        } catch(Throwable e) {
            // 异常处理
        }
    }
}

0x06 ysoserial中的动态代理应用

核心方法

// 创建带记忆功能的代理
public static <T> T createMemoitizedProxy(
    final Map<String, Object> map, 
    final Class<T> iface, 
    final Class<?>... ifaces
) throws Exception {
    return createProxy(
        createMemoizedInvocationHandler(map), 
        iface, 
        ifaces
    );
}

// 创建记忆型调用处理器
public static InvocationHandler createMemoizedInvocationHandler(
    final Map<String, Object> map
) throws Exception {
    return (InvocationHandler) Reflections.getFirstCtor(ANN_INV_HANDLER_CLASS)
        .newInstance(Override.class, map);
}

// 创建代理对象
public static <T> T createProxy(
    final InvocationHandler ih, 
    final Class<T> iface, 
    final Class<?>... ifaces
) {
    final Class<?>[] allIfaces = (Class<?>[]) Array.newInstance(
        Class.class, 
        ifaces.length + 1
    );
    allIfaces[0] = iface;
    if (ifaces.length > 0) {
        System.arraycopy(ifaces, 0, allIfaces, 1, ifaces.length);
    }
    return iface.cast(Proxy.newProxyInstance(
        Gadgets.class.getClassLoader(), 
        allIfaces, 
        ih
    ));
}

应用场景

  1. CommonsCollections1:
final Map mapProxy = Gadgets.createMemoitizedProxy(lazyMap, Map.class);
  1. RMIRegistryExploit:
Remote remote = Gadgets.createMemoitizedProxy(
    Gadgets.createMap(name, payload), 
    Remote.class
);
  1. Spring2:
final Object typeProviderProxy = Gadgets.createMemoitizedProxy(
    Gadgets.createMap("getType", typeTemplatesProxy),
    forName("org.springframework.core.SerializableTypeWrapper$TypeProvider")
);

0x07 总结

Java动态代理机制要点:

  1. 基于ProxyInvocationHandler实现
  2. 运行时动态生成代理类
  3. 方法调用通过invoke转发
  4. 广泛应用于安全研究领域

理解动态代理机制对后续学习RMI、JNDI注入等高级主题有重要帮助。

Java动态代理机制深入解析 0x01 前言 Java动态代理机制位于 java.lang.reflect.Proxy 包中,其本质是通过反射执行 invoke 方法来动态获取执行方法。与反射机制类似,动态代理也是Java安全研究中的重要组成部分。 0x02 代理模式概念 代理模式是Java中最常用的设计模式之一,其特征是: 代理类与委托类有同样的接口 代理类主要负责为委托类预处理消息、过滤消息、转发消息以及事后处理消息 Java代理机制分为: 静态代理:编译时确定代理关系 动态代理:运行时动态生成代理类 0x03 静态代理示例 接口定义 委托类实现 代理类实现 静态代理优缺点 优点 : 不改变委托类源代码即可扩展功能 缺点 : 接口变更时,委托类和代理类都需要修改 代理多个类时代理类数量会膨胀 不易维护和管理 0x04 Java动态代理核心组件 1. InvocationHandler接口 由代理对象调用处理器实现的接口 定义 invoke() 方法 代理对象上的方法调用会自动转发到 InvocationHandler.invoke() 2. Proxy类 提供四个静态方法: getProxyClass(ClassLoader,Class<?>...) :获取指定类加载器和接口的动态代理类 newProxyInstance(ClassLoader,Class<?>[],InvocationHandler) :创建代理实例 isProxyClass(Class<?>) :判断类是否为动态代理类 getInvocationHandler(Object) :获取代理类关联的调用处理器 0x05 动态代理实现过程 1. 创建调用处理器 2. 创建代理对象 3. 生成的代理类分析 生成的 $Proxy0.class 关键部分: 0x06 ysoserial中的动态代理应用 核心方法 应用场景 CommonsCollections1: RMIRegistryExploit: Spring2: 0x07 总结 Java动态代理机制要点: 基于 Proxy 和 InvocationHandler 实现 运行时动态生成代理类 方法调用通过 invoke 转发 广泛应用于安全研究领域 理解动态代理机制对后续学习RMI、JNDI注入等高级主题有重要帮助。