1.简介
Java远程方法调用,即Java RMI(Java Remote Method Invocation)是Java编程语言里,一种用于实现远程过程调用的应用程序编程接口。它使客户机上运行的程序可以调用远程服务器上的对象。远程方法调用特性使Java编程人员能够在网络环境中分布操作。RMI全部的宗旨就是尽可能简化远程接口对象的使用。接口的两种常见实现方式是:最初使用JRMP(Java Remote Message Protocol,Java远程消息交换协议)实现;此外还可以用与CORBA兼容的方法实现。RMI一般指的是编程接口,也有时候同时包括JRMP和API(应用程序编程接口),而RMI-IIOP则一般指RMI接口接管绝大部分的功能,以支持CORBA的实现。最初的RMI API设计为通用地支持不同形式的接口实现。后来,CORBA增加了传值(pass by value)功能,以实现RMI接口。然而RMI-IIOP和JRMP实现的接口并不完全一致。
2原理:
架构图:
RMI
底层通讯采用了Stub(运行在客户端)
和Skeleton(运行在服务端)
机制,RMI
调用远程方法的大致如下:
RMI客户端
在调用远程方法时会先创建Stub(sun.rmi.registry.RegistryImpl_Stub)
。Stub
会将Remote
对象传递给远程引用层(java.rmi.server.RemoteRef)
并创建java.rmi.server.RemoteCall(远程调用)
对象。RemoteCall
序列化RMI服务名称
、Remote
对象。RMI客户端
的远程引用层
传输RemoteCall
序列化后的请求信息通过Socket
连接的方式传输到RMI服务端
的远程引用层
。RMI服务端
的远程引用层(sun.rmi.server.UnicastServerRef)
收到请求会请求传递给Skeleton(sun.rmi.registry.RegistryImpl_Skel#dispatch)
。Skeleton
调用RemoteCall
反序列化RMI客户端
传过来的序列化。Skeleton
处理客户端请求:bind
、list
、lookup
、rebind
、unbind
,如果是lookup
则查找RMI服务名
绑定的接口对象,序列化该对象并通过RemoteCall
传输到客户端。RMI客户端
反序列化服务端结果,获取远程对象的引用。RMI客户端
调用远程方法,RMI服务端
反射调用RMI服务实现类
的对应方法并序列化执行结果返回给客户端。RMI客户端
反序列化RMI
远程方法调用结果。
参考:https://www.javasec.org/javase/RMI/
3代码示例
服务端
1 | package com.rmi; |
上述代码中,在8989端口起了RMI服务,以键值对的形式存储了RMI_PATH和rmiInterface的对应关系,也就是rmi://127.0.0.1:8989/hello对应一个ServicetestImpl类实例,然后通过Naming.rebind(RMI_NAME, rmiInterface)绑定对应关系。再来看Servicetest.java
1 | package com.rmi; |
定义了RMIInterface接口,继承自Remote,然后定义了一个test()方法作为接口。注意需要抛出RemoteException异常。继续看实现真正功能的类ServicetestImpl.java
1 | package com.rmi; |
继承自UnicastRemoteObject类,并且实现之前定义的Servicetest接口的test()方法。UnicastRemoteObject类提供了很多支持RMI的方法,具体来说,这些方法可以通过JRMP协议导出一个远程对象的引用,并通过动态代理构建一个可以和远程对象交互的Stub对象。现在就定义好了Server端,来看Client
1 | package com.rmi; |
参考:https://su18.org/post/rmi-attack/#2-%E6%94%BB%E5%87%BB-registry-%E7%AB%AF
https://paper.seebug.org/1091/#java-rmi_2
https://xz.aliyun.com/t/7079?time__1311=n4%2BxnD0Dy7itGQNKGNnmAzti%3DDkW3DB7in1oD
https://xz.aliyun.com/t/7264?time__1311=n4%2BxnD0Dy7G%3DBxGqGNnmADR7DgDfErrx3%2BBbD#toc-0
https://y4er.com/posts/java-rmi/
https://www.javasec.org/javase/RMI/
http://www.mi1k7ea.com/2019/09/01/Java-RMI%E5%8E%9F%E7%90%86%E4%B8%8E%E4%BD%BF%E7%94%A8/
https://www.cnblogs.com/nice0e3/p/14280278.html
https://www.bilibili.com/video/BV1L3411a7ax?p=5&vd_source=82398f68c82cb90e0d9aa4fea90e36a0
https://townmacro.cn/2022/04/18/java-%E5%AE%89%E5%85%A8-rmi%E5%AD%A6%E4%B9%A0%E6%80%BB%E7%BB%93/
https://su18.org/post/rmi-attack/#%E5%9B%9B-%E6%94%BB%E5%87%BB-rmi
https://xz.aliyun.com/t/7079?time__1311=n4%2BxnD0Dy7itGQNKGNnmAzKDtf%3D4AKDkWe6YeD
https://paper.seebug.org/1091/#java-rmi_2
https://forum.butian.net/share/2278
https://xz.aliyun.com/t/7264?time__1311=n4%2BxnD0Dy7G%3DBxGqGNnmADR7DgDfErrx3%2BBbD#toc-2
https://townmacro.cn/2022/04/18/java-%E5%AE%89%E5%85%A8-rmi%E5%AD%A6%E4%B9%A0%E6%80%BB%E7%BB%93/