概念
RMI(RemoteMethodInvocation,远程方法调用)在JDK1.2中实现,大大增强了Java开发分布式应用的能力。
Java本身对RMI规范的实现默认使用的是JRMP协议。而在Weblogic中对RMI规范的实现使用T3协议。
- JRMP:JavaRemoteMessageProtocol,Java远程消息交换协议。这是运行在Java RMI之下、TCP/IP之上的线路层协议。该协议要求服务端与客户端都为Java编写,就像HTTP协议一样,规定了客户端和服务端通信要满足的规范。
- JNDI:Java命名和目录接口(the Java naming and directory interface,JNDI)是一组在Java应用中访问命名和目录服务的API。命名服务将名称和对象联系起来,使得读者可以用名称访问对象。目录服务是一种命名服务,在这种服务里,对象不但有名称,还有属性。
RMI作用
RMI允许运行在一个Java虚拟机的对象调用运行在另一个Java虚拟机上的对象的方法。这两个虚拟机可以是运行在相同计算机上的不同进程中,也可以是运行在网络上的不同计算机中。
不同于socket,RMI中分为三大部分:Server、Client、Registry 。
1 | Server: 提供远程的对象 |
RMI基础运用
前面说过RMI可以调用远程的一个Java的对象进行本地执行,但是远程被调用的该类必须继承java.rmi.Remote
接口。
定义远程接口
1 | import java.rmi.Remote; |
在定义远程接口的时候需要继承java.rmi.Remote
接口,并且修饰符需要为public
否则远程调用的时候会报错。并且定义的方法里面需要抛出一个RemoteException
的异常。
编写远程接口实现类
1 | import java.rmi.RemoteException; |
在编写该实现类中需要将该类继承UnicastRemoteObject
。
创建服务器实例
并且创建一个注册表,将需要提供给客户端的对象注册到注册到注册表中
1 | import java.rmi.RemoteException; |
编写客户端
并且调用远程对象
1 | import java.rmi.NotBoundException; |
需要注意的是,如果远程的这个方法有参数的话,调用该方法传入的参数必须是可序列化的。在传输中是传输序列化后的数据,服务端会对客户端的输入进行反序列化。
RMI 反序列化攻击
需要使用到RM进行反序列化攻击需要两个条件:
- 接收Object类型的参数
- RMI的服务端存在执行命令利用链
这里对上面得代码做一个简单的改写。
远程接口代码
1 | import java.rmi.Remote; |
定义一个object类型的参数方法。
远程接口实现类代码
1 | import java.rmi.RemoteException; |
Server代码
1 | import java.rmi.RemoteException; |
Client代码
1 | import org.apache.commons.collections.Transformer; |
执行客户端后就会执行我们设置好要执行的命令,也就是弹出计算器。
原因:RMI在传输数据的时候,会被序列化,传输序列化后的数据,在传输完成后再进行反序列化。那么如果传输一个恶意的序列化数据就会进行反序列化的命令执行。