IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Java RMI 学习笔记 -> 正文阅读

[Java知识库]Java RMI 学习笔记

最近想学习一下Java相关的安全知识,就找了几篇文章来学习下,从Java RMI开始吧

什么是 JAVA RMI ?

RMI ( Remote Method Invocation , 远程方法调用 ) 能够让在某个 Java虚拟机 上的对象像调用本地对象一样调用另一个 Java虚拟机 中的对象上的方法 , 这两个 Java虚拟机 可以是运行在同一台计算机上的不同进程, 也可以是运行在网络中不同的计算机上 .

RMI分为三个主体部分:

Client-客户端:客户端调用服务端的方法

Server-服务端:远程调用方法对象的提供者,也是代码真正执行的地方,执行结束会返回给客户端一个方法执行的结果。

Registry-注册中心:其实本质就是一个map,相当于是字典一样,用于客户端查询要调用的方法的引用。

JAVA RMI 的流程 .

如果让客户端直接访问服务端的资源 , 那么有可能出现越权访问的风险 . 在 JAVA RMI 中 , 通过一个 中间人 来解决这类问题 .

服务端( RMIServer ) 会将自己提供的服务的实现类交给这个中间人 , 并公开一个名称 . 任何客户端( RMIClient )都可以通过公开的名称找到这个实现类 , 并调用它 .

这样以来 , 不仅避免了客户端和服务端资源的直接交互 . 也使得客户端能更好的查找要使用的对象( 直接去询问这个中间人 , 若中间人拥有对应实现类 , 那么客户端可以在本地直接调用该类的方法 . 若中间人没有对应的实现类 , 则说明服务端没有提供相应服务 )

这个中间人也被称为 RMIService / RMIRegister .

因此整个 RMI 的流程实际上分为三个部分 , RMIServer , RMIClient , RMIRegister . 其交互的流程如下所示 :

在这里插入图片描述

JAVA RMI 的简单例子

1.服务端编写一个远程接口

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

// 定义一个远程接口,继承java.rmi.Remote接口

public interface HelloInterface extends Remote {
    String Hello(String age) throws RemoteException;
}

既然 RMIServer 要提供服务 , 那么它一定会准备一个接口 , 让客户端通过这个接口来访问服务

需要说明的是 :

在 Java 中 , 如果一个类继承了 java.rmi.Remote 接口 , 那么该类将成为一个服务端的远程对象 , 供客户端访问并提供一定的服务 .

Remote 接口是一个标识接口 , 本身不包含任何方法 , 该接口用于标识其子类的方法可以被非本地的Java虚拟机调用

由于远程调用的本质依旧是 " 网络通信 " . 而网络通信是经常出现异常的 . 因此 , 继承 Remote 接口的接口的所有方法必须要抛出 RemoteException 异常 . 事实上 , RemoteException 也是继承于 IOException 的 .

2.要想调用远程接口 , 还需要一个实现类

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

// 远程接口实现类,继承UnicastRemoteObject类和Hello接口

public class HelloImp extends UnicastRemoteObject implements HelloInterface {

    private static final long serialVersionUID = 1L;

    protected HelloImp() throws RemoteException {
        super(); // 调用父类的构造函数
    }

    @Override
    public String Hello(String age) throws RemoteException {
        return "Hello" + age; // 改写Hello方法
    }
}

远程接口实现类必须继承UnicastRemoteObject类,用于生成 Stub(存根)和 Skeleton(骨架)。

Stub可以看作远程对象在本地的一个代理,囊括了远程对象的具体信息,客户端可以通过这个代理和服务端进行交互。

Skeleton可以看作为服务端的一个代理,用来处理Stub发送过来的请求,然后去调用客户端需要的请求方法,最终将方法执行结果返回给Stub。

其实 , 与其说是客户端和服务端进行交互 , 不如说是 客户端代理( Stub ) 和 服务端代理( Skeleton ) 在进行交互 .

同时跟进UnicastRemoteObject类源代码我们可以发现,其构造函数抛出了RemoteException异常。但这种写法是十分不好的,所以我们通过super()关键词调用父类的构造函数。

在这里插入图片描述

3.RMI服务器端

import java.rmi.Naming;
import java.rmi.registry.LocateRegistry;

// 服务端

public class RMIServer {
    public static void main(String[] args) {
        try {
            HelloInterface h  = new HelloImp(); // 创建远程对象HelloImp对象实例
            LocateRegistry.createRegistry(1099); // 获取RMI服务注册器
            Naming.rebind("rmi://localhost:1099/hello",h); // 绑定远程对象HelloImp到RMI服务注册器
            System.out.println("RMIServer start successful");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

LocateRegistry.createRegistry(1099); : 即在本地创建并启动 RMIService , 被创建的 RMIService 服务将会在指定的端口上监听请求 .

RMIService ( RMIRegister ) 服务的默认端口为 : 1099

java.rmi.Naming 类提供在对象注册表中存储和获得远程对远程对象引用的方法 . 这里将远程对象 " h " 绑定到 rmi://localhost:1099/hello 这个 URL 上 . 客户端可以通过这个 URL 直接访问远程对象 .

这里涉及到了另一个问题 : 即 " 开发人员不知道远程实例对象的名称是什么 ." 而通过这种绑定机制 , 开发人员仅需要知道一个公开的路径(URL) , 就可以直接访问到对应的远程对象了 .

4.RMI客户端配置

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

// 客户端

public class RMIClient {
    public static void main(String[] args){
        try {
            HelloInterface h = (HelloInterface) Naming.lookup("rmi://localhost:1099/hello"); // 寻找RMI实例远程对象
            System.out.println(h.Hello("run......"));
        }catch (MalformedURLException e) {
            System.out.println("url格式异常");
        } catch (RemoteException e) {
            System.out.println("创建对象异常");
        } catch (NotBoundException e) {
            System.out.println("对象未绑定");
        }
    }
}

客户端只需要调用 java.rmi.Naming.lookup 函数,通过公开的路径从RMIService服务器上拿到对应接口的实现类, 之后通过本地接口即可调用远程对象的方法 .

因此 , 只需要一个接口 , 一个客户端连接程序 , 即可实现 JAVA 远程调用 .

5.运行结果

在这里插入图片描述
在这里插入图片描述
通过结果也可以知道,这个方法的调用,实际上也还是在服务端,而不是客户端。

JAVA RMI的一些攻击

因为在整个RMI机制过程中,都是进行反序列化传输,我们可以利用这个特性使用RMI机制来对RMI远程服务器进行反序列化攻击。

但实现RMI利用反序列化攻击,需要满足两个条件:

1、接收Object类型参数的远程方法

2、RMI的服务端存在执行pop利用链的jar包

后续的实例就不试了,因为这篇文章就是自己的一个入门学习,暂时了解了相关原理和知道反序列化传输就行,想查看实例以及相关的通信原理的,可以查看下面的参考文章

https://www.guildhab.top/2020/03/java-rmi-ldap-%e6%b5%81%e7%a8%8b%e5%88%86%e6%9e%90/

https://xz.aliyun.com/t/9261

https://xz.aliyun.com/t/6660#toc-5

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-11-29 16:10:49  更:2021-11-29 16:12:38 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 3:24:49-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码