当前位置: 首页 > news >正文

[Java安全】JDK 动态代理

文章目录

    • 动态代理的两个主要类
      • InvocationHandler:调用处理程序
      • Proxy : 代理
    • 代码示例
    • 动态代理在反序列化中的作用

动态代理的两个主要类

jdk的动态代理主要需要了解两个类

  • InvocationHandler 调用处理程序类
  • Proxy 代理类

InvocationHandler:调用处理程序

public interface InvocationHandler

InvocationHandler是由代理实例调用处理程序实现的接口

每一个代理实例都有一个调用处理程序

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

当在代理实例上调用方法时,其实就会自动调用这个调用处理程序 invoke()

参数:

  • proxy : 代理实例对象
  • method: 当前被调用的方法对象,通过它可以获取方法名、参数类型等信息
  • args: 调用方法时传递的参数值

Proxy : 代理

public class Proxy extends Object implements Serializable

Proxy提供了创建动态代理类的和实例的静态方法,它也是由这个方法所创建的动态代理类的超类

动态代理类是一个实现 在类创建时 在运行时指定的接口列表的类

代理接口是由代理类实现的接口

代理实例是代理类的实例对象

public static Object newProxyInstance(ClassLoader loader,<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException

返回指定接口的代理类的实例,该接口将 方法调用 分派给指定的 调用处理程序

参数

  • loader: 类加载器来定义代理类
  • interfaces: 代理类实现的接口列表
  • h : 调度方法调用的调用处理函数

代码示例

两个要点

  • 代理的是接口,而不是单个用户
  • 代理类是动态生成的,而不是静态写死的

首先定义接口类: UserService.java

package DynamicProxy;public interface UserService {public void add();public void del();public void update();public void query();
}

接口类的具体实现: UserServiceImpl.java

package DynamicProxy;public class UserServiceImpl implements UserService{@Overridepublic void add() {System.out.println("增加一个用户");}@Overridepublic void del() {System.out.println("删除一个用户");}@Overridepublic void update() {System.out.println("更新一个用户");}@Overridepublic void query() {System.out.println("查询一个用户");}
}

然后是动态代理的实现类: UserProxyInvocationHandler.java

package DynamicProxy;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;public class UserProxyInvocationHandler implements InvocationHandler {//要代理的接口private Object target;public UserProxyInvocationHandler() {}public UserProxyInvocationHandler(Object target) {this.target = target;}//动态生成代理类public Object getProxy() {Object proxy = Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);return proxy;}//处理代理类的实例对象@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {log(method.getName());Object obj = method.invoke(target, args);return obj;}//自定义需求public void log(String msg){System.out.println("【+】调用"+msg+"方法");}}

最后就是启动器 Client.java

package DynamicProxy;public class Client {public static void main(String[] args) {//真实角色UserService userService = new UserServiceImpl();//代理角色UserProxyInvocationHandler userProxyInvocationHandler = new UserProxyInvocationHandler(userService);//代理类(动态生成)UserService proxy = (UserService) userProxyInvocationHandler.getProxy();proxy.add();proxy.update();proxy.del();proxy.query();}
}

在这里插入图片描述

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

利用反序列化的漏洞,是需要一个入口类的

先假设存在一个能够漏洞利用的类为 B.f,比如 Runtime.exec 这种。
我们将入口类定义为 A,我们最理想的情况是 A[O] -> O.f,那么我们将传进去的参数 O 替换为 B 即可。但是这种情况是很少见的,不会这么简单。

那么如果入口类 A 存在 O.abc 这个方法,也就是 A[O] -> O.abc;而 O 呢,如果是一个动态代理类,Oinvoke 方法里存在 .f 的方法,便可以漏洞利用了

动态代理对象调用方法时,其所有的方法调用都会自动路由到InvocationHandler.invoke()里面去,也就是前面比如调用 proay.add()它会路由到UserProxyInvocationHandler.invoke方法里面去,从而多调用了一个log()方法,也就是打印调用了哪个函数

A[O] -> O.abc
O[O2] invoke -> O2.f // 此时将 B 去替换 O2
最后  ---->
O[B] invoke -> B.f // 达到漏洞利用效果

参考

https://drun1baby.top/2022/06/01/Java%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E5%9F%BA%E7%A1%80%E7%AF%87-04-JDK%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86/
https://www.bilibili.com/video/BV1mc411h719?p=9
https://www.bilibili.com/video/BV16h411z7o9/?p=3&vd_source=cf7d01598010e70f1da4b79252417e78
http://www.lryc.cn/news/590206.html

相关文章:

  • 浅谈SQL注入注释符#和--+的运用场景和区别
  • rocky8 --Elasticsearch+Logstash+Filebeat+Kibana部署【7.1.1版本】
  • Hadoop(三)
  • Django REST Framework 入门指南:从 0 到 1 实现 RESTful API
  • 汇编 Call 指令运行原理详解:从跳转机制到堆栈操作
  • 基于 elements3 包装的 可展开 table 组件
  • uniapp各端通过webview实现互相通信
  • 并发编程-CountDownLatch
  • UniApp 多端人脸认证图片上传实现
  • 【PTA数据结构 | C语言版】前缀树的3个操作
  • 关于程序=数据结构+算法这句话最近的一些思考
  • 数字ic后端设计从入门到精通11(含fusion compiler, tcl教学)全定制设计入门
  • Java-数构链表
  • golang语法-----指针
  • 笔试——Day10
  • 简单易懂,什么是连续分配管理方式
  • Qt 将触摸事件转换为鼠标事件(Qt4和Qt5及以上版本)
  • Java线程创建与运行全解析
  • DuckDB 高效导入 IPv6 地址数据的实践与性能对比
  • #Datawhale组队学习#7月-强化学习Task1
  • java解析word文档
  • 使用JS编写一个购物车界面
  • C++ 面向对象
  • 第2章通用的高并发架构设计——2.3 高并发读场景方案2:本地缓存
  • 开源 python 应用 开发(七)数据可视化
  • Linux 定时器应用示例(修正版)
  • GIT版本回退
  • Python中可以反转的数据类型
  • GaussDB 数据库架构师修炼(五) 存储容量评估
  • 搜索框的显示与隐藏(展开与收起)