java rmi 安全_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的交互过程

java rmi 安全_Java安全初探-RMI篇_第1张图片

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

RMI 尝试

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

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

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

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

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

在 RMI 注册表中注册服务;

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

注意:这里踩了个小坑,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;

}

服务器输出

f44f5a85eaee01edcdbbbbad66be1436.png

客户端输出

cf84d9d0fac786abef5633e3fe2a0fdd.png

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

RMI数据包分析

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

java rmi 安全_Java安全初探-RMI篇_第2张图片

1-5为tcp三次握手和网关转发报文

6-12为RMI通信数据(其中TCP报文为确认报文)

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

java rmi 安全_Java安全初探-RMI篇_第3张图片

用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

在Object Serialization Stream Protocol文档中,可以发现TC_BLOCKDATA 这部分对应的是 contents -> content -> blockdata -> blockdatashort , TC_STRING 这部分对应的是 contents -> content -> object-> newString。整个序列化数据含义并不难猜,其实就是告诉我们获取远程的Hello对象。

接下来看看11号RMI ReturnData报文(返回远程对象)

java rmi 安全_Java安全初探-RMI篇_第4张图片

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

STREAM_MAGIC - 0xac ed

STREAM_VERSION - 0x00 05

Contents

TC_BLOCKDATA - 0x77

Length - 15 - 0x0f

Contents - 0x0175f02f4b00000170fd2fe646800e

TC_OBJECT - 0x73

TC_PROXYCLASSDESC - 0x7d

newHandle 0x00 7e 00 00

Interface count - 2 - 0x00 00 00 02

proxyInterfaceNames

0:

Length - 15 - 0x00 0f

Value - java.rmi.Remote - 0x6a6176612e726d692e52656d6f7465

1:

Length - 21 - 0x00 15

Value - org.test.Server.Hello - 0x6f72672e746573742e5365727665722e48656c6c6f

classAnnotations

TC_NULL - 0x70

TC_ENDBLOCKDATA - 0x78

superClassDesc

TC_CLASSDESC - 0x72

className

Length - 23 - 0x00 17

Value - java.lang.reflect.Proxy - 0x6a6176612e6c616e672e7265666c6563742e50726f7879

serialVersionUID - 0xe1 27 da 20 cc 10 43 cb

newHandle 0x00 7e 00 01

classDescFlags - 0x02 - SC_SERIALIZABLE

fieldCount - 1 - 0x00 01

Fields

0:

Object - L - 0x4c

fieldName

Length - 1 - 0x00 01

Value - h - 0x68

className1

TC_STRING - 0x74

newHandle 0x00 7e 00 02

Length - 37 - 0x00 25

Value - Ljava/lang/reflect/InvocationHandler; - 0x4c6a6176612f6c616e672f7265666c6563742f496e766f636174696f6e48616e646c65723b

classAnnotations

TC_NULL - 0x70

TC_ENDBLOCKDATA - 0x78

superClassDesc

TC_NULL - 0x70

newHandle 0x00 7e 00 03

classdata

java.lang.reflect.Proxy

values

h

(object)

TC_OBJECT - 0x73

TC_CLASSDESC - 0x72

className

Length - 45 - 0x00 2d

Value - java.rmi.server.RemoteObjectInvocationHandler - 0x6a6176612e726d692e7365727665722e52656d6f74654f626a656374496e766f636174696f6e48616e646c6572

serialVersionUID - 0x00 00 00 00 00 00 00 02

newHandle 0x00 7e 00 04

classDescFlags - 0x02 - SC_SERIALIZABLE

fieldCount - 0 - 0x00 00

classAnnotations

TC_NULL - 0x70

TC_ENDBLOCKDATA - 0x78

superClassDesc

TC_CLASSDESC - 0x72

className

Length - 28 - 0x00 1c

Value - java.rmi.server.RemoteObject - 0x6a6176612e726d692e7365727665722e52656d6f74654f626a656374

serialVersionUID - 0xd3 61 b4 91 0c 61 33 1e

newHandle 0x00 7e 00 05

classDescFlags - 0x03 - SC_WRITE_METHOD | SC_SERIALIZABLE

fieldCount - 0 - 0x00 00

classAnnotations

TC_NULL - 0x70

TC_ENDBLOCKDATA - 0x78

superClassDesc

TC_NULL - 0x70

newHandle 0x00 7e 00 06

classdata

java.rmi.server.RemoteObject

values

objectAnnotation

TC_BLOCKDATA - 0x77

Length - 56 - 0x38

Contents - 0x000a556e6963617374526566000f3139322e3136382e3234372e3132380000c3ec8f6141e4b20d3e0e75f02f4b00000170fd2fe646800101 #里面包含RMI Server和端口

TC_ENDBLOCKDATA - 0x78

java.rmi.server.RemoteObjectInvocationHandler

values

内容突然多了起来,不过看到一些跟java.lang.reflect.Proxy对象有关的东西,其实就是返回了调用远程方法的服务器地址和端口。怎么确定呢,观察后续tcp交互的报文即可知道。

java rmi 安全_Java安全初探-RMI篇_第5张图片

java rmi 安全_Java安全初探-RMI篇_第6张图片

再看19号数据包,也是一串aced开头的反序列数据

java rmi 安全_Java安全初探-RMI篇_第7张图片

丢进去工具分析一下序列化数据

F:\Java> java -jar .\SerializationDumper.jar 50aced000577220000000000000002000000000000000000000000000000000001f6b6898d8bf28643757200185b4c6a6176612e726d692e7365727665722e4f626a49443b871300b8d02c647e02000070787000000001737200156a6176612e726d692e7365727665722e4f626a4944a75efa128ddce55c0200024a00066f626a4e756d4c000573706163657400154c6a6176612f726d692f7365727665722f5549443b7078708f6141e4b20d3e0e737200136a6176612e726d692e7365727665722e5549440f12700dbf364f12020003530005636f756e744a000474696d65490006756e69717565707870800100000170fd2fe64675f02f4b77088000000000000000737200126a6176612e726d692e6467632e4c65617365b0b5e2660c4adc340200024a000576616c75654c0004766d69647400134c6a6176612f726d692f6467632f564d49443b70787000000000000927c0737200116a6176612e726d692e6467632e564d4944f8865bafa4a56db60200025b0004616464727400025b424c000375696471007e0003707870757200025b42acf317f8060854e002000070787000000008ed0c29a151acf1bb7371007e0005800100000170fd4ea68fcc0083e6

RMI Call - 0x50

STREAM_MAGIC - 0xac ed

STREAM_VERSION - 0x00 05

Contents

TC_BLOCKDATA - 0x77

Length - 34 - 0x22

Contents - 0x0000000000000002000000000000000000000000000000000001f6b6898d8bf28643

TC_ARRAY - 0x75

TC_CLASSDESC - 0x72

className

Length - 24 - 0x00 18

Value - [Ljava.rmi.server.ObjID; - 0x5b4c6a6176612e726d692e7365727665722e4f626a49443b

serialVersionUID - 0x87 13 00 b8 d0 2c 64 7e

newHandle 0x00 7e 00 00

classDescFlags - 0x02 - SC_SERIALIZABLE

fieldCount - 0 - 0x00 00

classAnnotations

TC_NULL - 0x70

TC_ENDBLOCKDATA - 0x78

superClassDesc

TC_NULL - 0x70

newHandle 0x00 7e 00 01

Array size - 1 - 0x00 00 00 01

Values

Index 0:

(object)

TC_OBJECT - 0x73

TC_CLASSDESC - 0x72

className

Length - 21 - 0x00 15

Value - java.rmi.server.ObjID - 0x6a6176612e726d692e7365727665722e4f626a4944

serialVersionUID - 0xa7 5e fa 12 8d dc e5 5c

newHandle 0x00 7e 00 02

classDescFlags - 0x02 - SC_SERIALIZABLE

fieldCount - 2 - 0x00 02

Fields

0:

Long - L - 0x4a

fieldName

Length - 6 - 0x00 06

Value - objNum - 0x6f626a4e756d

1:

Object - L - 0x4c

fieldName

Length - 5 - 0x00 05

Value - space - 0x7370616365

className1

TC_STRING - 0x74

newHandle 0x00 7e 00 03

Length - 21 - 0x00 15

Value - Ljava/rmi/server/UID; - 0x4c6a6176612f726d692f7365727665722f5549443b

classAnnotations

TC_NULL - 0x70

TC_ENDBLOCKDATA - 0x78

superClassDesc

TC_NULL - 0x70

newHandle 0x00 7e 00 04

classdata

java.rmi.server.ObjID

values

objNum

(long)-72056500129022450 - 0x8f 61 41 e4 b2 0d 3e 0e

space

(object)

TC_OBJECT - 0x73

TC_CLASSDESC - 0x72

className

Length - 19 - 0x00 13

Value - java.rmi.server.UID - 0x6a6176612e726d692e7365727665722e554944

serialVersionUID - 0x0f 12 70 0d bf 36 4f 12

newHandle 0x00 7e 00 05

classDescFlags - 0x02 - SC_SERIALIZABLE

fieldCount - 3 - 0x00 03

Fields

0:

Short - S - 0x53

fieldName

Length - 5 - 0x00 05

Value - count - 0x636f756e74

1:

Long - L - 0x4a

fieldName

Length - 4 - 0x00 04

Value - time - 0x74696d65

2:

Int - I - 0x49

fieldName

Length - 6 - 0x00 06

Value - unique - 0x756e69717565

classAnnotations

TC_NULL - 0x70

TC_ENDBLOCKDATA - 0x78

superClassDesc

TC_NULL - 0x70

newHandle 0x00 7e 00 06

classdata

java.rmi.server.UID

values

count

(short)-32767 - 0x80 01

time

(long)-47192506 - 0x00 00 01 70 fd 2f e6 46

unique

(int)1978675019 - 0x75 f0 2f 4b

TC_BLOCKDATA - 0x77

Length - 8 - 0x08

Contents - 0x8000000000000000

TC_OBJECT - 0x73

TC_CLASSDESC - 0x72

className

Length - 18 - 0x00 12

Value - java.rmi.dgc.Lease - 0x6a6176612e726d692e6467632e4c65617365

serialVersionUID - 0xb0 b5 e2 66 0c 4a dc 34

newHandle 0x00 7e 00 07

classDescFlags - 0x02 - SC_SERIALIZABLE

fieldCount - 2 - 0x00 02

Fields

0:

Long - L - 0x4a

fieldName

Length - 5 - 0x00 05

Value - value - 0x76616c7565

1:

Object - L - 0x4c

fieldName

Length - 4 - 0x00 04

Value - vmid - 0x766d6964

className1

TC_STRING - 0x74

newHandle 0x00 7e 00 08

Length - 19 - 0x00 13

Value - Ljava/rmi/dgc/VMID; - 0x4c6a6176612f726d692f6467632f564d49443b

classAnnotations

TC_NULL - 0x70

TC_ENDBLOCKDATA - 0x78

superClassDesc

TC_NULL - 0x70

newHandle 0x00 7e 00 09

classdata

java.rmi.dgc.Lease

values

value

(long)600000 - 0x00 00 00 00 00 09 27 c0

vmid

(object)

TC_OBJECT - 0x73

TC_CLASSDESC - 0x72

className

Length - 17 - 0x00 11

Value - java.rmi.dgc.VMID - 0x6a6176612e726d692e6467632e564d4944

serialVersionUID - 0xf8 86 5b af a4 a5 6d b6

newHandle 0x00 7e 00 0a

classDescFlags - 0x02 - SC_SERIALIZABLE

fieldCount - 2 - 0x00 02

Fields

0:

Array - [ - 0x5b

fieldName

Length - 4 - 0x00 04

Value - addr - 0x61646472

className1

TC_STRING - 0x74

newHandle 0x00 7e 00 0b

Length - 2 - 0x00 02

Value - [B - 0x5b42

1:

Object - L - 0x4c

fieldName

Length - 3 - 0x00 03

Value - uid - 0x756964

className1

TC_REFERENCE - 0x71

Handle - 8257539 - 0x00 7e 00 03

classAnnotations

TC_NULL - 0x70

TC_ENDBLOCKDATA - 0x78

superClassDesc

TC_NULL - 0x70

newHandle 0x00 7e 00 0c

classdata

java.rmi.dgc.VMID

values

addr

(array)

TC_ARRAY - 0x75

TC_CLASSDESC - 0x72

className

Length - 2 - 0x00 02

Value - [B - 0x5b42

serialVersionUID - 0xac f3 17 f8 06 08 54 e0

newHandle 0x00 7e 00 0d

classDescFlags - 0x02 - SC_SERIALIZABLE

fieldCount - 0 - 0x00 00

classAnnotations

TC_NULL - 0x70

TC_ENDBLOCKDATA - 0x78

superClassDesc

TC_NULL - 0x70

newHandle 0x00 7e 00 0e

Array size - 8 - 0x00 00 00 08

Values

Index 0:

(byte)-19 - 0xed

Index 1:

(byte)12 - 0x0c

Index 2:

(byte)41 (ASCII: )) - 0x29

Index 3:

(byte)-95 - 0xa1

Index 4:

(byte)81 (ASCII: Q) - 0x51

Index 5:

(byte)-84 - 0xac

Index 6:

(byte)-15 - 0xf1

Index 7:

(byte)-69 - 0xbb

uid

(object)

TC_OBJECT - 0x73

TC_REFERENCE - 0x71

Handle - 8257541 - 0x00 7e 00 05

newHandle 0x00 7e 00 0f

classdata

java.rmi.server.UID

values

count

(short)-32767 - 0x80 01

time

(long)-45177201 - 0x00 00 01 70 fd 4e a6 8f

unique

(int)-872381466 - 0xcc 00 83 e6

数据太多,基于自身知识有限,先留个坑(别打我,真不会哇,后面专门开一篇文章分析本篇文章的几份序列化数据,不过通过这波抓包分析流程,结合上面的流程图,相信大家对RMI调用流程也有一定的理解了。

相关链接

你可能感兴趣的:(java,rmi,安全)