Java安全初探-RMI篇

Java RMI初识

Java RMI 定义

Java RMI(Java Remote Method Invocation),即Java远程方法调用。是Java编程语言里,一种用于实现远程过程调用的应用程序编程接口。 Java RMI 使用 JRMP(Java Remote Message Protocol,Java远程消息交换协议)实现,使得客户端运行的程序可以调用远程服务器上的对象。是实现RPC的一种方式。

JRMP:Java Remote Message Protocol ,Java 远程消息交换协议。这是运行在Java RMI之下、TCP/IP之上的线路层协议。

注:Java RMI默认使用JRMP协议,而Weblogic RMI使用的是T3协议,此处应进行区分

RMI的交互

此处引用文章JAVA RMI 原理和使用浅析的一张图演示RMI的交互过程

对于RMI流程的解释,网上有很多不错的回答,此处不过多阐述。通俗来讲,便是RMI Registry作为client和server的中间人,假设服务端是商品仓库,客户端是购买者,则RMI Registry就是中介,只负责告诉客户可以售卖的商品相关信息。仓库在中介处登记可售商品,客户从中介处查看可购买的商品。客户从中介处获得商品的相关信息,然后交给跑腿(存根stub)去跟仓库人员(骨架skeleton)取货,双方商品信息确认一致,进行交易,客户获得商品。(可能比喻有点不恰当,别揍我qwq...

RMI 尝试

此处为了更能体会rmi原理,不把server和client放在同一个机器,而是将服务器放在虚拟机中,测试环境均为1.8u211

  1. 编写远程服务接口,该接口必须继承 java.rmi.Remote 接口,方法必须抛出java.rmi.RemoteException 异常;

  2. 编写远程接口实现类,该实现类必须继承 java.rmi.server.UnicastRemoteObject 类;

  3. 运行 RMI 编译器(rmic),创建客户端 stub 类和服务端 skeleton 类;

  4. 启动一个 RMI 注册表,以便驻留这些服务;

  5. 在 RMI 注册表中注册服务;

  6. 客户端查找远程对象,并调用远程方法;

注意:这里踩了个小坑,RMI 抛出异常 no security manager: RMI class loader disabled,新手容易遇到这个问题。这是因为在编译class文件的时候,这个class文件内部已经包含了package test.org;这样的内容,如果在部署的时候,不严格按照这个目录部署的话,服务器就会找不到。所以服务器和客户端在路径上要保持一致。

Server测试例

org
└─test
├─RMI
│ RMIServer.java

└─Server
Hello.java

//RMIServer.java
package org.test.RMI;

import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.server.UnicastRemoteObject;

import org.test.Server.Hello;

public class RMIServer {
    public class RemoteHelloWorld extends UnicastRemoteObject implements Hello {
        protected RemoteHelloWorld() throws RemoteException {
            super();
        }
        public String hello() throws RemoteException {
            System.out.println("call from");
            return "Hello DEADF1SH_CAT~";
        }
    }

    private void start() throws Exception {
        RemoteHelloWorld h = new RemoteHelloWorld();
        LocateRegistry.createRegistry(1099);
        Naming.rebind("rmi://127.0.0.1:1099/Hello", h);
    }
    
    public static void main(String[] args) throws Exception {
        new RMIServer().start();
    }
}
//Hello.java
package org.test.Server;

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

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

Client测试例

org
└─test
├─client
│ TrainMain.java

└─Server
Hello.java

//TrainMain.java
package org.test.client;

import java.rmi.Naming;

import org.test.Server.Hello;

public class TrainMain {
    public static void main(String[] args) throws Exception {
        Hello hello = (Hello) Naming.lookup("rmi://192.168.247.128:1099/Hello");
        String ret = hello.hello();
        System.out.println(ret);
    }
}
//Hello.java
package org.test.Server;

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

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

服务器输出


客户端输出


可以看出客户端成功调用了服务器的RemoteHelloWorld对象的hello方法

RMI数据包分析

对上述调用过程进行抓包分析


  • 1-5为tcp三次握手和网关转发报文
  • 6-12为RMI通信数据(其中TCP报文为确认报文)

来看看9号RMI Call报文(远程对象请求)


SerializationDumper这个工具对Java序列化数据进行分析

F:\Java>java -jar SerializationDumper.jar aced00057722000000000000000000000000000000000000000000000000000244154dc9d4e63bdf74000548656c6c6f

STREAM_MAGIC - 0xac ed
STREAM_VERSION - 0x00 05
Contents
  TC_BLOCKDATA - 0x77
    Length - 34 - 0x22
    Contents - 0x000000000000000000000000000000000000000000000000000244154dc9d4e63bdf
  TC_STRING - 0x74
    newHandle 0x00 7e 00 00
    Length - 5 - 0x00 05
    Value - Hello - 0x48656c6c6f

相关链接

猜你喜欢

转载自www.cnblogs.com/DEADF1SH-CAT/p/12543598.html
今日推荐