介绍
本篇主要介绍java的RMI、JNDI、LDAP,在后面会详细分析log4j的jndi注入原理。
什么是RMI
RMI全称是RemoteMethodInvocatioon,也就是远程方法调用,看起来和RPC(RemoteProcedureCall)很像实际上它俩的确很像,RMI算是JAVA定制版RPC吧
一个完整的RMI调用过程,需要下面几个部分
注册服务
RMIServer
客户端
接口
实现接口的类
执行流程如下
首先开启注册服务
RMI创建实现接口的类的对象,并在注册服务中注册
客户端从注册服务调用接口里的方法
先来个例子,说不多说,都在代码里(网上找的)注册服务代码
1、网络安全学习路线2、电子书籍(白帽子)3、安全大厂内部视频4、份src文档5、常见安全面试题6、ctf大赛经典题目解析7、全套工具包8、应急响应笔记
接口和实现接口的类RMI服务客户端
运行流程如下图
此图和上面的代码对应关系
Client-Client存根(stub)-Client代码中的remoteHello对象(是个代理类,在通过它调用方法时,会将参数,函数名等信息打包,发送给骨架,存根对象包含了RMIServer的端口和ip)rmiregistry-RegServeerServer-RMI骨架(Skeleton)-也是个代理类,监听端口,用于和存根通信,收到存根的请求后,去调用RemoteImp对应的方法,然后将结果返回给存根ServiceImpl-RemoteImpl
所以,再以上面的代码为例,解读下执行流程
先启动Register服务(默认端口)
RMI去连接Register服务,并将Name和存根发送给Register服务如图
Client连接Register服务,根据Name获取到对应存根,再通过存根调用sayHello("World"),因为存根是代理类,所以可以获取到函数名,参数,参数类型等信息,存根将这些信息打包,发给骨架
RMI的骨架也是代理类,通过反射调用remoteHello.sayHello("World"),获取返回值Hello,World,并发送给存根
Client的存根将从骨架获取到的返回值Return,这样Client端看起来就好像调用的是本地的方法
补充下,以上步骤,通过网络传输的数据都是通过序列化对象的形式,使用的协议是JRMP(JavaRemoteMethodProtocol)协议很重要!!!
上面的代码还可以写成简化版如图服务端,在启动注册中心的同时,设置了存根和名字客户端,通过url连接注册中心,获取存根
什么是JNDI
JNDI全称是JavaNamingandDirectoryInterfac,翻译过来就是java命名和目录接口.实际上,这里的Naming指命名服务,Directory指目录服务。
命名服务
就是通过对资源的命名,便于下次调用资源更方便(所以这里的Naming要唯一)。例如上面的例子中的注册服务,就属于命名服务将Hello绑定RemoteImpl对象,在使用时,直接通过名字Hello就可以获取到RemoteImpl的存根。
命名服务就像下面这个清单,为每一个名字绑定了一个资源。
目录服务
和命名服务很像,但更复杂,可以理解为一个清单,清单上有各种资源,每个资源又有自己的清单。举个例子,例如清单上有10台电脑,我选中一台小李的电脑,会获取到下一张清单,列出了小李电脑上的资源如:网络邻居、打印机、C盘等等,我打开网络邻居,又获得一张清单。
根据上面的例子可以发现,这个目录服务,和计算机上的目录很像,打开一个文件夹,可以看见下一层目录,再打开一个文件夹,又可以看见下一层目录。我们熟知的dns就是目录服务,那它为什么属于目录服务,而不属于命名服务呢?
DNS服务
虽然在我们看来,通过域名,返回ip,特别像命名服务,但理解下dns解析过程就知道原因了。如图,在查询dns时,本地dns服务器去请求dns根服务器然后再请求.