3 安全
在一个典型的基于Jini技术的应用中,一个客户端从某处(例如,从一个lookup service或者一个与其他服务通讯的结果中)得到服务代理,然后调用那个代理的方法与服务进行通讯。许多应用需要对远程的通讯进行加密。那就需要以下的一个或几个技术:
* Mutual authentication(client and server)
* Authorization(access checksums)
* Integrity(cryptograhic checksums)
* Confidentiallity(encryption)
这些实典型加密数据通讯的需求;但是Jini安全模型有一个附加的需要:代码完整性检查(code integrity)。在Jini和Java RMI模型中一个对象的数据是在一个远程调用中得到的,但是他的代码是作为那个远程调用的的结果在带外(out-of-band)下载得到的。一个应用需要通过两方面确认它所收到的对象的信任信息:对象代码的完整性,以及它的数据的完整性。
**********************************************************************************************************
带外(out-of-band)的概念不是很理解参考以下网管中in-band和out-of-ban的区别吧:
in-band & out-of-band
从技术的角度,网络管理可分为带外管理(out-of-band )和带内管理(in-band )两种管理模式。所谓带内管理,是指网络的管理控制信息与用户网络的承载业务信息通过同一个逻辑信道传送;而在带外管理模式中,网络的管理控制信息与用户网络的承载业务信息在不同的逻辑信道传送。一般说来,由于传送信息的隔离,带外管理比带内管理安全程度更高。
带外数据(OOB:Out-Of-Band)
转自:iSeries信息中心
带外(00B)数据是特定于用户的数据,仅对面向连接的(流)套接字有意义。流数据通常是按发送次序接收的。OOB 数据的接收与它在流中的位置无关(与发送它的次序无关)。这是有可能的,原因是数据是按以下方式标记的,在将数据从程序 A 发送至程序 B 时,会通知程序 B 数据到达。
OOB 数据仅在 AF_INET(SOCK_STREAM)和 AF_INET6(SOCK_STREAM)上受支持。
通过在 send()、sendto() 和 sendmsg() 函数上指定 MSG_OOB 标志来发送 OOB 数据。
传送 OOB 数据与传送常规数据一样。它是在所有缓冲数据之后发送的。换句话说,OOB 数据的优先级别没有可能缓冲的任何数据的优先级别高;数据是按其发送次序传送的。
在接收端,事情有一点复杂:
●套接字 API 通过使用 OOB 标记程序了解在系统上接收到的 OOB 数据。OOB 标记程序指向发送的 OOB 数据中的最后一个字节。(注意:指示 OOB 标记程序指向哪个字节的值是在系统基础上设置的。此值在 TCP 连接的本地和远程端必须一致。使用此值的套接字应用程序在使用它时必须在客户机和服务器应用程序之间保持一致。)
SIOCATMARK ioctl() 请求确定读指针是否正指向最后一个 OOB 字节。(注意:如果发送多次出现的 OOB 数据,则 OOB 标记程序指向最后一次 OOB 数据出现的最后一个 OOB 字节。)
●无论 OOB 数据是否以直接插入方式接收,输入操作会一直处理数据直至遇到 OOB 标记程序(如果发送了 OOB 数据的话)。
●recv()、recvmsg() 或 recvfrom() 函数(设置有 MSG_OOB 标志)用于接收 OOB 数据。如果其中一个接收函数完成并发生下列情况之一,会返回错误 [EINVAL]。
1、未设置套接字选项 SO_OOBINLINE,也没有 OOB 数据可接收。
2、设置了套接字选项 SO_OOBINLINE。
如果未设置套接字选项 SO_OOBINLINE,且发送程序发送的 OOB 数据的大小超过 1 字节,则除最后一个字节之外的所有字节都被视作普通数据。(普通数据表示接收程序可接收数据而不指定 MSG_OOB 标志。)发送的 OOB 数据的最后一个字节未存储在普通数据流中。只能发出 recv()、recvmsg() 或 recvfrom() 函数(设置有 MSG_OOB 标志)来检索此字节。如果未设置 MSG_OOB 标志而发出接收,将检索普通数据,OOB 字节将被删除。而且,如果发送多次出现的 OOB 数据,则先前出现的 OOB 数据将会丢失,仅记住最后一次 OOB 数据出现的 OOB 数据位置。
如果设置了套接字选项 SO_OOBINLINE,则发送的所有 OOB 数据都存储在普通数据流中。可通过发出下列三个接收函数之一而不指定 MSG_OOB 标志(如果指定它的话,将返回错误 [EINVAL])来检索数据。如果发送多次出现的 OOB 数据,OOB 数据不会丢失。
●如果未设置 SO_OOBINLINE 且已接收到 OOB 数据,则不会废弃 OOB 数据,用户会将 SO_OOBINLINE 设置为开。初始 OOB 字节被视作普通数据。
●如果未设置 SO_OOBINLINE 且已发送 OOB 数据,同时接收程序发出了输入函数以接收 OOB 数据,则 OOB 标记程序仍然有效。接收程序仍然可以检查读指针是否在 OOB 标记程序上,即使接收到 OOB 字节。
************************************************************************************************************
这个发行版本提供了一个框架用来做信任验证信息,以及一个基于约束的(constraint-based)远程调用模型来使得使得应用可以对远程调用指定不同的需求(比如安全需求)。底层框架同时也提供了代码完整性检查(code integrity)的基础部分。
3.1 约束和远程调用
上面描述的安全需求可以被表示成远程调用的约束。一个约束就是一个客户端指定的应用于代理与它的服务之间的远程通讯的行为特征需求。一个代理可以通过实现net.jini.core.constraint.RemoteMethodControl接口来使得客户端能够为代理的远程通讯指定约束。基于约束的远程调用模型是概要(general)的,提供与安全相关的约束类型以及其他的约束类型。
一个使用约束的例子就是客户端需要在于一个服务通过代理通讯之前鉴别一个服务(比如一个银行)的标识。在这个例子中,服务的代理可以通过实现RemoteMethodControl接口来使得客户端对任何一个通过该代理执行的远程调用设置服务器鉴别的约束。满足这些约束是代理的职责,但是是否能够相信代理带来的信任信息确实客户端的职责。
每个约束都被表现为一个net.jini.core.constrait.InvocationConstraint的接口。一个InvacationConstraint的实例表示"what"但不是"how";也就是说,一个约束代表着这个约束象征着"什么"("what"),而不是代表着这个约束应该如何被满足。一个代理有责任使用正确的传输和协议来满足客户端所设置的约束。因为约束是被抽象的表述的,安全实现是可插入的,因此是有能力支持各种不同的协议的,比如SSL,和Kerberos。请参看net.jini.core.constraint的包文档来查找更多的有关pre-defined基础约束。
在一个客户端给代理设置一个约束前,客户端首先要确认这个代理是一个可被信任用来执行约束的代理。因为代理也许是从一个不被信任的源头得到的。如果客户端不确认代理的信任度,那么代理可以忽略client设置的约束并且执行非加密的数据传输,从而泄露client或者server的身份信息,甚至更遭。当客户端确认了代理的信任信息后,它就可以对代理设置约束来制定任何的安全需要,比如服务器的证明。
一旦客户端信任了一个代理,他可能还需要授予代理附加的许可。因为通常没有取得信任的代码都被事先配置了最低的许可,通过附加许可可以使得该代理以后的调用被正确执行。一个代理也许会请求net.jini.security.AuthenticationPermision,从而它可以验证服务器。一个客户端一定不能在认证一个代理之前授予其许可。从而确保不会产生代理滥用授权带来的危害。
总结一下,当一个客户端从未信任的源头取得代理后,需要在执行代理的方法前按照以下的步骤"prepare"代理。以下各个步骤地全部的需要在net.jini.security包文档中有详细描述:
* 确认代理的信任信息
* 为代理授权
* 给代理设置约束
以上的步骤可以被打包在一个独立的操作中---proxy preparation,这个术语意味着“为代理的远程调用做准备”。客户端的接口net.jini.security.ProxyPreparer将这些代理准备工作打包进了一个独立的方法,prepareProxy。
net.jini.security.BasicProxyPreparer类,一个ProxyPreparer接口的标准实现,在准备一个代理的远程调用前执行三个必须的步骤。大多数的开发人员可以使用BasicProxyPreparer实例来进行代理的准备工作,而不必关系信任信息确认背后的所有细节(下面解释一些细节)。如果其他的应用需要对信任信息确认,设置约束,以及授权的行为作定制的话可以继承BasicProxyPreparer。
3.2 使用BasicProxyPreparer进行代理准备
BasicProxyPreparer类封装了信任信息确认,设置约束,为代理授权这三个步骤。一个BasicaProxyPreparer实例可以用不同的方式进行构造,支持一下列出的很多通用的代理准备用例:
* 信任信息确认,为代理授权,设置新的约束:给一个从没有取得信任的源头得到的代理做准备。
* 设置新的约束:给一个从已经取得信任的源头(但是该源头还没有被确认支持指定的约束)得到的具有完整性保护的已经信任的代理做准备。
* 授权:给一个从已经取得信任的源头(并且该源头已经被确认支持指定的约束)得到的具有完整性保护的已经信任的代理做准备。
* 什么也不做:当查询一个可选的配置实体时被用来当作默认的动作。或者被用来准备一个不具有安全性的代理。
net.jini.security的静态的方法Security.verifyObjectTrust和Security.grant分别实现了信任信息确认和授权。约束可以通过调用实现了RemoteMethodControl接口的代理中的setConstraints方法进行设定。一个BasicProxyPreparer使用这三个机制来实现指定的代理准备。
下面的三个段落描述了BasicProxyPreparer实例使用这三个步骤进行代理准备的机制。处于讨论的目的,让我们假设这个BasicProxyPrepare实例是按照如下方式进行构造的:
new BasicProxyPreparer(true,constraints,permissions)
参数true,指出代理应该被验证信任信息,constraints是一个MethodConstraints对象(这是一个设给代理的包含了per-method约束的对象)。permissions参数是一个java.security.Permissions的数组,这些Permissions将被用来给代理授权。
以下的UML时序图说明了带了准备,和信任信息确认的处理过程。
Proxy Preparation:说明信任信息确认,授权,以及为代理设置新的约束。
Non-Smart代理信任信息确认:说明如何使用一个ProxyTrustVerifier来确认non-smart代理(例如一个简单的Jini ERI代理)的信任信息。
Smart代理的信任信息确认:说明如何使用ProxyTrustVerifier来确认一个smart代理的信任信息。