首页 > 编程语言 >javasec(六)RMI

javasec(六)RMI

时间:2023-04-19 17:56:08浏览次数:43  
标签:rmi java javasec Registry import RMI 远程

这篇文章介绍java-RMI远程方法调用机制。

RMI全称是Remote Method Invocation,远程⽅法调⽤。是让某个Java虚拟机上的对象调⽤另⼀个Java虚拟机中对象上的⽅法,只不过RMI是Java独有的⼀种RPC方法。看这篇之前可以先去看看RPC:https://www.bilibili.com/video/BV1zE41147Zq?from=search&seid=13740626242455157002

RMI流程

RMI远程⽅法调⽤的流程:
img
先介绍各个部分的功能作用:

  • Stub:客户端调用一个被称为 Stub (存根)的客户端代理对象。该代理对象负责对客户端隐藏网络通讯的细节。Stub 写着如何通过网络套接字(Socket)发送调用,包括如何将调用参数转换为适当的形式以便传输等。简单理解就是封装了一层网络传输的细节,直接传入参数调用就行。
  • Skeleton:在服务端中该代理对象负责对分布式对象隐藏网络通讯的细节。Skeleton 知道如何从网络套接字(Socket)中接受调用,包括如何将调用参数从网络传输形式转换为 Java 形式等。
  • Registry:注册中心,服务端在注册中心注册服务时,需要提供一个key以及一个value,这个value是一个远程对象,Registry会对这个远程对象进行封装,使其转为一个远程代理对象,它本身不会执行方法。在低版本的JDK中,Server与Registry是可以不在一台服务器上的,而在高版本的JDK中,Server与Registry只能在一台服务器上,否则无法注册成功
  • 注:
  1. Java对远程访问RMI Registry做了限制,只有来源地址是localhost的时候,才能调用rebind、bind、unbind等方法。
  2. 不过list和lookup方法可以远程调用。
  3. list方法可以列出目标上所有绑定的对象;lookup作用就是获得某个远程对象。

那么,只要目标服务器上存在一些危险方法,我们通过RMI就可以对其进行调用。

利用工具:https://github.com/NickstaDB/BaRMIe

建立RMI的流程如下

  1. 通过分析需求定义远程接口(客户端和服务器端公用的),此接口必须扩展java.rmi.Remote,且远程方法必须声明抛出 java.rmi.RemoteException 异常,或者该异常的超类(Superclass)
  2. 服务器端实现远程接口,为了不手动生成stub需要继承UnicastRemoteObject类,并调用其构造器;
  3. 服务器端注册服务并启动;
  4. 客户端查询服务并调用远程方法;

代码实现

分别建立三个项目:服务器端(RMIDemoServer)、客户端(RMIDemoClient)和远程接口(DemoRMI.RmoteInterface)

img

DemoRMI.RmoteInterface

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface HelloRMI extends Remote {

    String sayHello(String name) throws RemoteException;
}
//继承了 java.rmi.Remote 的接⼝,其中定义我们要远程调⽤的函数,⽐如这⾥的  sayHello(String name)

RMIDemoServer

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;

@SuppressWarnings("serial")
public class RMIHelloImpl extends UnicastRemoteObject implements HelloRMI {

    protected RMIHelloImpl() throws RemoteException {
        super();
    }

    public String sayHello(String name) {
        return "Hello,"+name;
    }
}

//实现了接⼝的类 这里输出Hello 传入的值
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;

public class SerApp
{
    public static void main( String[] args ) throws RemoteException, MalformedURLException
    {
        HelloRMI hello= (HelloRMI) new RMIHelloImpl();

        LocateRegistry.createRegistry(1099);
        Naming.rebind("rmi://127.0.0.1/hello", hello);
        System.out.println("Server ok");
    }
}

//创建Registry,并将实现类实例化后绑定到⼀个地址。这两部分就是我们所谓的Server

RMIDemoClient

import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;

public class ClientApp {
    public static void main( String[] args ) throws MalformedURLException, RemoteException, NotBoundException
    {
        HelloRMI hello=(HelloRMI) Naming.lookup("rmi://127.0.0.1/hello");
        System.out.println( hello.sayHello("Roderick RMI"));
    }
}

//客户端就简单多了,使⽤ Naming.lookup 在Registry中寻找到名字是hello的对象,调用hello.sayHello

简单说一下这个流程:首先定义公共的接口HelloRMI,然后服务端创建实现类RMIHelloImpl,同时创建Registry并将实现类实例化后绑定到⼀个地址。这样RMI的Server就算完成了,再直接启动SerApp。客户端直接用Naming.lookup去访问Registry获取对象,然后像使用本地方法一样使用RMI来的方法即可方法。启动ClientApp可以看到完成了RMI整个调用过程。

img借用p牛的解说:

“过程进行了了两次TCP握手,也就是我们实际建立了两次TCP连接。第⼀一次建立TCP连接是连接远端的1099端口,这也是我们在代码⾥里里看到的端口,⼆二者进行沟通后,我向远端发送了一个“Call”消息,远端回复了一个“ReturnData”消息,然后我新建了一个TCP连接,连到远端的33769端口。所以捋一捋这整个过程,首先客户端连接Registry,并在其中寻找Name是Hello的对象,这个对应数据流中的Call消息;然后Registry返回一个序列化的数据,这个就是找到的Name=hello的对象,这个对应数据流中的ReturnData消息;客户端反序列化该对象,发现该对象是一个远程对象,地址在x.x.x.x:端口,于是再与这个地址建⽴立TCP连接;在这个新的连接中,才执行真正远程方法调⽤用,也就是hello()。”

借用下图来说明这些元素间的关系:

imgRMI Registry就像一个网关,他自己是不不会执行远程方法的,但RMI Server可以在上⾯面注册一个Name到对象的绑定关系;RMI Client通过Name向RMI Registry查询,得到这个绑定关系,然后再连接RMIServer;最后,远程方法实际上在RMI Server上调用。

一个枚举和攻击 Java RMI(远程方法调用)服务的工具:https://github.com/NickstaDB/BaRMIe

标签:rmi,java,javasec,Registry,import,RMI,远程
From: https://www.cnblogs.com/uf9n1x/p/17334126.html

相关文章

  • centos登陆报错:System is booting up. Unprivileged users are not permitted to log
    问题:开机后ssh到服务器出现此报错,大概意思是系统正在启动中非授权用户不允许登录,解决:不需要处理,等会儿系统彻底起来后重新登陆就没有了,对应文件在/run/nologin ......
  • Java RMI与RPC,JMS的比较
    JavaRMI与RPC,JMS的比较远程对象方法调用并不是新概念,远程过程调用(RPC)已经使用很多年了。远程过程调用被设计为在应用程序间通信的平台中立的方式,它不理会操作系统之间以及语言之间的差异。即RPC支持多种语言,而RMI只支持Java写的应用程序。[1]另外RMI调用远程对象方法,允......
  • rpc rmi区别
    1.RMI和RPC之间最主要的区别在于方法是如何别调用的。在RMI中,远程接口使每个远程方法都具有方法签名。如果一个方法在服务器上执行,但是没有相匹配的签名被添加到这个远程接口上,那么这个新方法就不能被RMI客户方所调用。在RPC中,当一个请求到达RPC服务器时,这个请求就包含了一个参......
  • java反序列化(四) RMI反序列化
    RMIRMI(RemoteMethodInvocation),为远程方法调用,是允许运行在一个Java虚拟机的对象调用运行在另一个Java虚拟机上的对象的方法。这两个虚拟机可以是运行在相同计算机上的不同进程中,也可以是运行在网络上的不同计算机中。注册中心是一个特殊的服务端,一般与服务端在同一主机上......
  • 腾讯云服务 运行Docker 命令 报错 -bash: /usr/bin/docker: Permission denied
    一、报错信息-bash:/usr/bin/docker:Permissiondenied二、解决方案网上的解决方案https://blog.csdn.net/Bingorl/article/details/123349837我试了但是无效最后究极解决方案:重置腾讯云服务重装Docker  SUCCESS!!!!!!!!!!!!!!!!!......
  • 给deepin-terminal提交的pr
    hello,[email protected]以下是给deepin-teminal提交的pr:终端增加透明与非透明切换快捷键[https://github.com/linuxdeepin/deepin-terminal/pull/268]因需求面问题,未通过终端增加加粗下划线光标设置选项[https://github.com/linuxdeepin/deepin-termina......
  • GnuTLS recv error (-110): The TLS connection was non-properly terminated问题的解
    1. sudoapt-getupdate2.sudoapt-getinstallbuild-essentialfakerootdpkg-dev3.sudoapt-getbuild-depgit4.mkdir~/git-openssl5.cd~/git-openssl6apt-getsourcegit ......
  • platformio+esp32 编译时下载PACKAGES错误 Tool Manager ERROR
    如图,readtimeoutToolManegerl:Lookingforanothermirror.....  编译时一共需要三个[email protected](2.04)[email protected](3.0.0)[email protected]+2021r2-patch3都存在下载时超时,一直找寻......
  • ubuntu上安装docker-compose遇到Permission denied问题
    根据github.com/docker/compose/releases中安装compose的说明,在ubuntu上执行以下安装命令:curl-L https://github.com/docker/compose/releases/download/v2.17.2/docker-compose-$(uname-s)-$(uname-m)"-o/usr/local/bin/docker-compose命令执行返回的结果是:-bash:/usr/......
  • delphi 11.3 java.ioexception:cleartext http traffic [IP地址] not permitted
    要在AndroidManifest.xml添加如下属性即可:参考:HowtoFixCleartextHTTPTrafficnotPermittedinAndroid-TRENDOCEANS ......