RMI注入(一)

291 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

首先咱们得对java有个了解,很多入门都不知道java是干嘛的,java是一个什么语言

java是一门面向对象的编程语言,在java中对象通常包括实例变量和方法两种属性

实例变量:他代表的是一种状态(数据),并且同一个类型的多个对象都独立地拥有这些状态,我们把对象看作类的一个实例

方法:我们在构造一个类的时候,除了初始化类的状态,还要构造出可以操作这种状态的方法。类不是对象,类是用来构造对象的。

JNDI

这个是java naming and directory interface的缩写(JAVA命名和目录接口)。这个东西的作用主要是为java应用程序提供命名和目录访问服务的API(应用程序编程入口)。 JNDI就是定义一个数据源,与系统外部资源的引用,都可以通过JNDI定义和引用

咱们学习JAVA反序列化的时候,经常遇到RMI,JNDI,LDAP这些概念 RMI: 基于序列化的java远程方法调用机制,作为一个常见的反序列化入口,它和反序列化漏洞的关系很大

RMI

java RMI 即远程方法调用(Remote Method Invocation) 是一种用于实现远程调用RPC(Remote procedure call)的java api,它能够直接传输序列化后的java对象和分布式垃圾收集。 他的实现依赖于JAVA虚拟机(JVM)。因此它仅支持从一个JVM到另一个JVM的调用

image.png 上面是RMI架构图

首先咱们从服务端入手,要提供一个rmi服务端不需要额外引入依赖,直接使用类似于我们常见的rpc框架,先提供一个接口,重点注意它需要继承接口对应的实现类。最后就是启动服务,提供一个上面的接口。

一个完整的RMI调用过程:

注册服务
RMIServer
客户端
接口
实现接口的类
流程就是首先开启注册服务,RMI创建实现接口的类的对象,客户端从注册服务调用接口里的方法

接口和实现接口的类

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

public interface RemoteIntF extends Remote {
    String sayhello(String name) throws RemoteException;
}

对于RMI

import java.io.IOException;
import java.rmi.AlreadyBoundException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;

public class RMI {
    public static void main(String[] args) {
      RemoteImp remoteHello = new RemoteImp();
      try {
          RemoteIntF stub = (RemoteIntF) UnicastRemoteObject.exportObject(remoteHello,  port 4000); //这里是导出服务,使用的4000端口
          Registry registry = LocateRegistry.getRegistry(host: "127.0.0.1",port: 8000); //获取Registry
          Registry.bind(name: "hello",stub); //使用名字hello,将服务注册到Regisstry
          }catch (AlreadyBoundExceptioin | IOException e) {
             e.printStackTrace();
          }
    }
}

Client -> Client存根(stub) -> Client代码中的remoteHello对象(是一个代理类,在通过它调用方法时,会将参数,函数名等信息打包,发送给骨架,存根对象包含了RMIServer的端口和IP) -> RegServeerServer -> RMI骨架(Skeleton) -> 也是个代理类,监听4000端口,用于和存根通信,收到存根的请求后,去调用RemoteImp对应的方法,然后将结果返回给ServiceImpl -> RemoteImpl