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(); // 调用委托类方法
}
}
静态代理优缺点
优点:
- 不改变委托类源代码即可扩展功能
缺点:
- 接口变更时,委托类和代理类都需要修改
- 代理多个类时代理类数量会膨胀
- 不易维护和管理
0x04 Java动态代理核心组件
1. InvocationHandler接口
- 由代理对象调用处理器实现的接口
- 定义
invoke()方法 - 代理对象上的方法调用会自动转发到
InvocationHandler.invoke()
2. Proxy类
提供四个静态方法:
getProxyClass(ClassLoader,Class<?>...):获取指定类加载器和接口的动态代理类newProxyInstance(ClassLoader,Class<?>[],InvocationHandler):创建代理实例isProxyClass(Class<?>):判断类是否为动态代理类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
));
}
应用场景
- CommonsCollections1:
final Map mapProxy = Gadgets.createMemoitizedProxy(lazyMap, Map.class);
- RMIRegistryExploit:
Remote remote = Gadgets.createMemoitizedProxy(
Gadgets.createMap(name, payload),
Remote.class
);
- Spring2:
final Object typeProviderProxy = Gadgets.createMemoitizedProxy(
Gadgets.createMap("getType", typeTemplatesProxy),
forName("org.springframework.core.SerializableTypeWrapper$TypeProvider")
);
0x07 总结
Java动态代理机制要点:
- 基于
Proxy和InvocationHandler实现 - 运行时动态生成代理类
- 方法调用通过
invoke转发 - 广泛应用于安全研究领域
理解动态代理机制对后续学习RMI、JNDI注入等高级主题有重要帮助。