基于kerberos的分布式计算平台安全
发布日期:2021-10-04 19:50:16 浏览次数:2 分类:技术文章

本文共 19324 字,大约阅读时间需要 64 分钟。

基于kerberos的分布式计算平台安全

简介

Apache基金会开源项目,分布式计算基础架构Hadoop收到越来越多的重视。基于Hadoo和HDFS的分布式计算架构的使用越来越广泛。Hadoop 首先作为 的子项目 Nutch 的一部分正式引入。它受到最先由Google开发的MapReduce和GFS的启发。

但是Hadoop在设计实现的时候没有考虑过安全性的问题。因此,Hadoop中存在着很多安全性漏洞,这使得分布式计算平台安全收到了极大的威胁。其中最大的问题就是,HDFS中存储的数据是没有安全限制的,意即,只要能提交一个任务(job),就能通过该任务访问HDFS上所有的数据。

Kerberos是由MIT设计并开发的一套三方安全认证协议,并已写入RFC标准。目前最新的标准时Krb5。Kerberos通过第三方可信机构KDC对需要通信的双方进行认证。由于其详尽的设计,使其可以应对大多数攻击方法。而不由KDC存储会话秘钥和会话过程不由KDC参与的特性,使其具有非常高的性能。

Java StandardEdition (J2SE)使用了kerberos v5实现了单点登录,增强了Java安全架构的能力。单点登录允许用户认证一次就可以获得多个系统的服务。这是通过JAAS的认证授权机制以及Java GSSAPI在两个对等实体之间建立安全通信环境实现的。由于JAAS和JavaGSSAPI良好的封装性,将JAAS以及JavaGSSAPI应用到Hadoop中,可以在尽量少改动源代码的情况下实现Hadoop安全。

作为Hadoop最早的使用者之一,Yahoo!率先在Hadoop安全方面做出了贡献。通过引入kerberos作为底层的认证授权机制,Yahoo!在用户认证,用户访问远程服务的授权,以及用户访问控制方面实现了一部分Hadoop安全。

本文的首要目标是使用kerberos作为底层安全机制,在用户任务提交、运行,以及HDFS文件访问控制方面实现Hadoop安全。

问题明确

本节明确本文需要研究的内容和解决问题可能的方法。

研究Hadoop的任务提交、分发机制。

研究kerberos的具体机制,认证方法以及相应的名词。

研究kerberos安装及使用方法。对kerberos安装,用户使用以及管理员使用分别作出一定的描述。

研究JAAS和JavaGSSAPI原理和使用方法。

Kerberos认证过程

Kerberos的三个子过程

通过以上的介绍,我们基本上了解了整个Kerberos authentication的整个流程:整个流程大体上包含以下3个子过程:

Client向KDC申请TGT(Ticket Granting Ticket)。

Client通过获得TGT向DKC申请用于访问Server的Ticket。

Client最终向为了Server对自己的认证向其提交Ticket。

不过上面的介绍离真正的Kerberos Authentication还是有一点出入。Kerberos整个认证过程通过3个sub-protocol来完成。这个3个Sub-Protocol分别完成上面列出的3个子过程。这3个sub-protocol分别为:

AuthenticationService Exchange

TicketGranting Service Exchange

Client/ServerExchange

下图简单展示了完成这个3个Sub-protocol所进行Message Exchange。

1. Authentication Service Exchange

通过这个Sub-protocol,KDC(确切地说是KDC中的AuthenticationService)实现对Client身份的确认,并颁发给该Client一个TGT。具体过程如下:

Client向KDC的AuthenticationService发送Authentication Service Request(KRB_AS_REQ),为了确保KRB_AS_REQ仅限于自己和KDC知道,Client使用自己的Master Key对KRB_AS_REQ的主体部分进行加密(KDC可以通过Domain的Account Database获得该Client的MasterKey)。KRB_AS_REQ的大体包含以下的内容:

Pre-authenticationdata:包含用以证明自己身份的信息。说白了,就是证明自己知道自己声称的那个account的Password。一般地,它的内容是一个被Client的Masterkey加密过的Timestamp。

Client name& realm: 简单地说就是Domain name\Client

Server Name:注意这里的Server Name并不是Client真正要访问的Server的名称,而我们也说了TGT是和Server无关的(Client只能使用Ticket,而不是TGT去访问Server)。这里的Server Name实际上是KDC的Ticket Granting Service的Server Name。

AS(Authentication Service)通过它接收到的KRB_AS_REQ验证发送方的是否是在Client name & realm中声称的那个人,也就是说要验证发送放是否知道Client的Password。所以AS只需从AccountDatabase中提取Client对应的MasterKey对Pre-authentication data进行解密,如果是一个合法的Timestamp,则可以证明发送放提供的是正确无误的密码。验证通过之后,AS将一份AuthenticationService Response(KRB_AS_REP)发送给Client。KRB_AS_REQ主要包含两个部分:本Client的MasterKey加密过的Session Key(SKDC-Client:Logon Session Key)和被自己(KDC)加密的TGT。而TGT大体又包含以下的内容:

Session Key:SKDC-Client:Logon Session Key

Client name& realm: 简单地说就是Domain name\Client

End time:TGT到期的时间。

Client通过自己的Master Key对第一部分解密获得Session Key(SKDC-Client:Logon Session Key)之后,携带着TGT便可以进入下一步:TGS(TicketGranting Service)Exchange。

2. TGS(TicketGranting Service)Exchange

TGS(Ticket Granting Service)Exchange通过Client向KDC中的TGS(Ticket Granting Service)发送Ticket Granting Service Request(KRB_TGS_REQ)开始。KRB_TGS_REQ大体包含以下的内容:

TGT:Client通过ASExchange获得的Ticket Granting Ticket,TGT被KDC的Master Key进行加密。

Authenticator:用以证明当初TGT的拥有者是否就是自己,所以它必须以TGT的办法方和自己的Session Key(SKDC-Client:Logon Session Key)来进行加密。

Client name& realm: 简单地说就是Domain name\Client。

Server name& realm: 简单地说就是Domain name\Server,这回是Client试图访问的那个Server。

TGS收到KRB_TGS_REQ在发给Client真正的Ticket之前,先得整个Client提供的那个TGT是否是AS颁发给它的。于是它不得不通过Client提供的Authenticator来证明。但是Authentication是通过LogonSession Key(SKDC-Client)进行加密的,而自己并没有保存这个Session Key。所以TGS先得通过自己的Master Key对Client提供的TGT进行解密,从而获得这个Logon Session Key(SKDC-Client),再通过这个Logon Session Key(SKDC-Client)解密Authenticator进行验证。验证通过向对方发送Ticket Granting Service Response(KRB_TGS_REP)。这个KRB_TGS_REP有两部分组成:使用Logon Session Key(SKDC-Client)加密过用于Client和Server的Session Key(SServer-Client)和使用Server的MasterKey进行加密的Ticket。该Ticket大体包含以下一些内容:

Session Key:SServer-Client。

Client name& realm: 简单地说就是Domain name\Client。

End time:Ticket的到期时间。

Client收到KRB_TGS_REP,使用LogonSession Key(SKDC-Client)解密第一部分后获得Session Key(SServer-Client)。有了Session Key和Ticket,Client就可以之间和Server进行交互,而无须在通过KDC作中间人了。所以我们说Kerberos是一种高效的认证方式,它可以直接通过Client和Server双方来完成,不像Windows NT 4下的NTLM认证方式,每次认证都要通过一个双方信任的第3方来完成。

我们现在来看看 Client如果使用Ticket和Server怎样进行交互的,这个阶段通过我们的第3个Sub-protocol来完成:CS(Client/Server)Exchange。

3. CS(Client/Server)Exchange

这个已经在本文的第二节中已经介绍过,对于重复发内容就不再累赘了。Client通过TGSExchange获得Client和Server的Session Key(SServer-Client),随后创建用于证明自己就是Ticket的真正所有者的Authenticator,并使用SessionKey(SServer-Client)进行加密。最后将这个被加密过的Authenticator和Ticket作为Application Service Request(KRB_AP_REQ)发送给Server。除了上述两项内容之外,KRB_AP_REQ还包含一个Flag用于表示Client是否需要进行双向验证(Mutual Authentication)。

Server接收到KRB_AP_REQ之后,通过自己的Master Key解密Ticket,从而获得Session Key(SServer-Client)。通过Session Key(SServer-Client)解密Authenticator,进而验证对方的身份。验证成功,让Client访问需要访问的资源,否则直接拒绝对方的请求。

对于需要进行双向验证,Server从Authenticator提取Timestamp,使用SessionKey(SServer-Client)进行加密,并将其发送给Client用于Client验证Server的身份。

User to user子过程

通过3个Sub-protocol的介绍,我们可以全面地掌握整个Kerberos的认证过程。实际上,在Windows 2000时代,基于Kerberos的WindowsAuthentication就是按照这样的工作流程来进行的。但是我在上面一节结束的时候也说了,基于3个Sub-protocol的Kerberos作为一种NetworkAuthentication是具有它自己的局限和安全隐患的。我在整篇文章一直在强调这样的一个原则:以某个Entity的Long-termKey加密的数据不应该在网络中传递。原因很简单,所有的加密算法都不能保证100%的安全,对加密的数据进行解密只是一个时间的过程,最大限度地提供安全保障的做法就是:使用一个Short-term key(SessionKey)代替Long-term Key对数据进行加密,使得恶意用户对其解密获得加密的Key时,该Key早已失效。但是对于3个Sub-Protocol的C/S Exchange,Client携带的Ticket却是被ServerMaster Key进行加密的,这显现不符合我们提出的原则,降低Server的安全系数。

所以我们必须寻求一种解决方案来解决上面的问题。这个解决方案很明显:就是采用一个Short-term的SessionKey,而不是Server Master Key对Ticket进行加密。这就是我们今天要介绍的Kerberos的第4个Sub-protocol:User2UserProtocol。我们知道,既然是Session Key,仅必然涉及到两方,而在Kerberos整个认证过程涉及到3方:Client、Server和KDC,所以用于加密Ticket的只可能是Server和KDC之间的Session Key(SKDC-Server)。

我们知道Client通过在ASExchange阶段获得的TGT从KDC那么获得访问Server的Ticket。原来的Ticket是通过Server的Master Key进行加密的,而这个Master Key可以通过AccountDatabase获得。但是现在KDC需要使用Server和KDC之间的SKDC-Server进行加密,而KDC是不会维护这个Session Key,所以这个Session Key只能靠申请Ticket的Client提供。所以在AS Exchange和TGSExchange之间,Client还得对Server进行请求已获得Server和KDC之间的Session Key(SKDC-Server)。而对于Server来说,它可以像Client一样通过ASExchange获得他和KDC之间的SessionKey(SKDC-Server)和一个封装了这个Session Key并被KDC的Master Key进行加密的TGT,一旦获得这个TGT,Server会缓存它,以待Client对它的请求。我们现在来详细地讨论这一过程。

上图基本上翻译了基于User2User的认证过程,这个过程由4个步骤组成。我们发现较之我在上面一节介绍的基于传统3个Sub-protocol的认证过程,这次对了第2部。我们从头到尾简单地过一遍:

AS Exchange:Client通过此过程获得了属于自己的TGT,有了此TGT,Client可凭此向KDC申请用于访问某个Server的Ticket。

这一步的主要任务是获得封装了Server和KDC的Session Key(SKDC-Server)的属于Server的TGT。如果该TGT存在于Server的缓存中,则Server会直接将其返回给Client。否则通过AS Exchange从KDC获取。

TGS Exchange:Client通过向KDC提供自己的TGT,Server的TGT以及Authenticator向KDC申请用于访问Server的Ticket。KDC使用先用自己的Master Key解密Client的TGT获得SKDC-Client,通过SKDC-Client解密Authenticator验证发送者是否是TGT的真正拥有者,验证通过再用自己的Master Key解密Server的TGT获得KDC和Server 的SessionKey(SKDC-Server),并用该Session Key加密Ticket返回给Client。

C/S Exchange:Client携带者通过KDC和Server的Session Key(SKDC-Server)进行加密的Ticket和通过Client和Server的SessionKey(SServer-Client)的Authenticator访问Server,Server通过SKDC-Server解密Ticket获得SServer-Client,通过SServer-Client解密Authenticator实现对Client的验证。

kerberos安装及使用方法

具体安装过程不详述。仅说明几点需要注意的地方。

Realm

Realm是kerberos中“域”的概念。通常,一个主KDC管辖一个域。在一个intranet中,通常都是使用一个域名,例如example.com,这种情况下,域的名称就被设为域名的大写形式EXAMPLE.COM。

如果你有多个域,MIT建议使用易于记忆的形式,例如LOCATION.EXAMPLE.COM。

Principal

Kerberos中的principal即上文所提到的申请ticket时用到的唯一身份标识。总体来说,有两大类不同的principal。

。如果用户是管理员,。

其他类型的principal,较少用到。

Database

Kerberos的主KDC上有一个管理用户的数据库,这个数据库只存在于主KDC,只能由管理员来管理。数据库主要用来添加删除principal等重要管理工作。

下图示例了如何建立一个kerberos database,注意域的名称是EXAMPLE.COM:

shell%/usr/local/sbin/kdb5_util create -r EXAMPLE.COM -s

Initializing database'/usr/local/var/krb5kdc/principal' for

⇒ realm ' EXAMPLE.COM',

master key name 'K/M@ EXAMPLE.COM'

You will be prompted for the databaseMaster Password.

It is important that you NOT FORGET thispassword.

Enter KDC database master key: <= Type the master password.

Re-enter KDC database master key toverify: <= Type it again.

shell%

ACL

Kerberos的ACL不用于我们要应用到分布式计算系统中的ACL。ACL(Access Control List)在这里的作用是用于限定一台装有kerberos服务的机器上,何种principal对kerberos数据库做何种操作。

ACL文件的路径和名称在kdc.conf中配置。默认路径和名称为/usr/local/var/krb5kd/ kadm5.acl。ACL文件对kerberos的安全性有很重要的作用,所以建议只有root权限可以修改该文件。

ACL文件格式为:

Kerberos_principal permissions [target_principal] [restrictions]

Kerberos_principal和target_principal两项可以使用‘*’号作为通配符。例如对所有具有admin权限的principal给予对数据库所有操作的权限,可以使用‘*/admin@EXAMPLE.COM’的方法。

Permission选项分别限制数据库的以下操作:‘admcils’对数据库的操作分别是“添加、删除、修改、更换密码、查询、列出所有、允许对principal显式设置key”,上述英文字母的大写形式表示禁止这种权限。

Keytab

Keytab可以理解为密钥cache。Keytab一般给service使用,这样service在认证自己或者给客户端认证的时候,不用输入密钥。该文件是加密的,存储在服务器的本地磁盘上。Keytab文件的默认路径是/etc/krb5.keytab。

下图示例了如何建立一个keytab文件,该文件允许location.example.com这个服务器认证sample服务:

location% /usr/local/sbin/kadmin
kadmin5: ktadd sample/location.example.com@EXAMPLE.COM
kadmin: Entry for principal sample/location.example.com @EXAMPLE.COM
with kvno 3, encryption type DES-CBC-CRC added to keytab
WRFILE:/etc/krb5.keytab.
kadmin5: quit
location %

Clientconfigure

客户端配置时需要注意的一点是,如果服务端和客户端不在一个机器上,那么客户端需要在其/etc/services文件中添加所需服务的条目。

Serverconfigure

服务器配置的时候需要注意,一定要有keytab文件,并且keytab文件中有所需的服务的entry在里面。可以通过klist –k查看默认keytab中有哪些principal的entry。

JavaAuthentication and Authorization Service

JAAS提供了一种可扩展的能力。针对认证和基于认证实体的访问控制,JAAS提供了一种可插卸的框架和编程接口。

JAAS框架可以分成两个部分,一是认证组件,一是授权组件。JAAS认证组件提供安全确认当前代码运行用户的身份的能力,不论这段代码是Application,Applet,bean还是servlet。JAAS授权组件增加了安全可靠性,提供了代码执行的限制。特定代码只能由特定用户执行。

JAAS认证框架基于可插卸认证模块(Pluggable Authentication Module)。基于这种架构,系统管理员可以以插卸的方式增加或者减少认证模块。这使得Java程序可以独立于底层的认证机制。新认证模块的增加可以避免修改代码,只需修改配置文件即可。

JAAS认证框架同时支持可堆叠模块。多种安全模块可以以配置文件中指定的顺序调用。

Subject是JAAS中属于,它指代任何请求访问资源的实体。一个subject可能是一个用户或者一个服务。由于一个实体可能会有很多名字或者principal,JAAS使用subject作为一个上层的封装。因此,一个subject中会有一堆principal。

Subject中也会有一些安全相关的credential,这些credential中有公有的,也有私有的。敏感的数据存储在私有集合中。Subject类有一些方法可以检索principal,以及其对应的公有credential或者私有credential。

Java2使用java.lang.SecurityManager增强了运行时访问控制。在任何敏感操作发生时,SecurityManager都会进行审查。SecurityManager将审查授权给java.security.AccessController去做。AccessController会获得一个AccessControlContext的运行时镜像,来检查操作是否有效。

JAAS提供了两个方法doAs和doAsPrivileged去实现一个subject和AccessControlContext的动态关联。doAs方法关联subject和当前线程访问控制环境,随后的访问控制检查基于代码运行的方法以及运行这段代码的subject。doAsPrivileged基本上和doAs相同,除了前者可以指定一个线程环境。

由于访问控制环境是基于线程的,JVM中不同的线程可以看做不同的实体。一个访问控制环境关联的subject可以通过getSubject函数获得。

LoginContext类提供了基本的subject认证方法。它使得应用程序独立于具体的认证机制。LoginContext通过查看配置文件决定使用何种认证方法。如果没有指定认证方法,默认选择配置文件中的“other”条目。

LoginModule为了支持堆叠式的认证方式,LoginContext通过两个阶段来认证subject。第一个阶段中,程序会尝试调用所有配置过的认证方法,如果所有的认证模块调用通过,那么进入第二个阶段,再次调用这些模块提供正式的认证请求。在这个阶段中,subject会存储所有的principal以及相应的credential。如果中间任意一次失败,程序会逐步释放所有的存储空间并销毁相应条目。

由JAAS调用的登录模块需要一个回调函数接收一些信息。例如kerberos登录时需要用户输入用户名和密码来认证。LoginContext允许应用程序指定回调函数和用户进行交互。

Sun提供了UnixLoginModule, NTLoginModule,JNDILoginModule, KeyStoreLoginModule 以及Krb5LoginModule 这几种登录模块的实现。com.sun.security.auth.module.Krb5LoginModule类是Sun对kerberosv5登录模块的实现。一旦认证成功,TGT会存储到subject的私有credential集合中,principal会存储到subject的principal集合中。

根据配置文件中的信息,Krb5LoginModule可以使用已经存在的credential的缓存,例如操作系统中的本地缓存获得TGT,或者使用keytab文件中存储的密钥隐式的认证一个principal。在所有的平台上,Krb5LoginModule允许在配置文件中指定缓存文件的地址或者keytab文件的路径。在没有上述文件的情况下,会弹出用户名和密码的输入提示。

下面两个图分别是客户端和服务器配置文件书写方式:

SampleClient {
com.sun.security.auth.module.Krb5LoginModule required useTicketCache=true;
};
SampleServer {
com.sun.security.auth.module.Krb5LoginModule
required useKeyTab=true storeKey=true principal="nfs/bar.foo.com" keyTab="/etc/krb5.keytab" doNotPrompt=true;
};

为了使其他供应商提供的kerberos认证模块也能在GSS-API中使用,在javax.security.auth.kerberos包中有三个类需要介绍。

l KerberosPrincipal用来处理principal。

l KerberosKey用来处理long-termkey,即用户的密码。

l KerberosTicket 用来处理ticket。

任何kerberos登录木块的相关内容都要使用这三个类包装。

Java GenericSecurity Service Application Program Interface

GSS-API

企业级应用程序通常需要多种安全需求,并且在底层部署了大量的安全机制。在这种情况下,如何开发客户端服务器程序,使之可以在不同的底层安全机制下轻松的移植?GSS-API实现了这样一种应用程序和底层具体实现之间的隔离。GSS-API是由IETF通用认证技术工作组设计的,提出了几种对等实体间安全通信的程序接口。

GSS-API在RFC 2743中可以查到,提供了以下几种安全服务:认证、信息的机密性和完整性、受保护的消息序列、重放检测以及credential代理。底层的实现有众多的选择。IETF定义了两种标准的安全机制:kerberos v5以及SimplePublic Key Mechanism(SPKM)。

API设计成可以同时使用多种底层安全机制,并且是应用程序可以在运行时选择。底层机制由在IANA注册的统一对象标识符(OID)表示。例如,kerberos v5的标识为{iso(1)member-body(2) United States(840) mit(113554) infosys(1) gssapi(2) krb5(2)}即(1.2.840.113554.1.2.2)。下图是多种底层安全机制的GSS-API实现。

Java GSS-API

通用安全服务Java版同样也在IETF有定义,并存储在RFC2853中。在Java社区进程(Java Community Process)的基础上,Sun公司追求这套API的标准化。最初的Java GSS-API的实现是只支持kerberos v5的,尽管它支持其他的底层机制,但是kerberos v5是必选的。在将来的发行版中,会添加一个服务提供接口(Service Provide Interface),新的底层机制可以静态的甚至运行时配置。Java GSS-API框架本身是非常轻巧的,所有的安全功能都委托给底层的安全机制。

GSSManager类了解所有安装的底层安全机制,并负责调用这些模块。其对象可以通过下面的方式获得:

GSSManagermanager = GSSManager.getInstance();

GSSManager可以用来配置新的安全机制,或者列出所有已经存在的安全机制。同时它还作为三个重要接口的工厂类,分别是GSSName、GSSCredential和 GSSContext。GSS-API的调用会抛出GSSException异常,这些异常类封装了GSS-API框架本身的问题以及底层安全机制的问题。

GSSNameInterface

该接口代表Java GSS-API中的一个实体实例化的方法如下:

GSSNameGSSManager.createName(String name, Oid nameType) throws GSSException

GSSNameclientName = manager.createName("root", GSSName.NT_USER_NAME);

GSSNameserverName = manager.createName("sample@location.example.com",

GSSName.NT_HOSTBASED_SERVICE);

这个调用返回一个principal的合法格式,并且屏蔽了底层安全机制。例如在kerberos v5机制下,,第二个例子生成的principal是服务的principal:sample/location.example.com@EXAMPLE.COM。

类似地,底层安全机制是公钥加密机制的话,上述principal会被映射为X.509形式。

GSSCredentialInterface

该接口封装了实体所有的credential,同GSSName接口相同,该接口是一个多层安全机制的容器。其实例化方法如下:

GSSCredential createCredential(GSSName name,int lifetime, Oid[] desiredMechs, int usage) throwsGSSException

GSSCredential clientCreds =

manager.createCredential(clientName,

8*3600,

desiredMechs,

GSSCredential.INITIATE_ONLY);

GSSCredential serverCreds =

manager.createCredential(serverName,

GSSCredential.INDEFINITE_LIFETIME,

desiredMechs,

GSSCredential.ACCEPT_ONLY);

GSSManager调用desiredMechs中所列出的底层安全机制的模块来申请对应principal的credential。此外,加强了安全性的限制,credential必须是initial类型的,生命周期只有八小时。返回的对象中包含相应安全机制认证后的credential。Kerberosv5机制下返回的元素是javax.security.auth.kerberos.KerberosTicket子类的实例,包含用户相关的TGT。

服务器端程序基本相同,除了credential的类型是accept类型的,同时,服务器的credential一般都会申请一个较长生命周期的。

Credential的几个基本属性如下:

l :仅用于安全会话环境接受。

l :仅用于安全会话环境初始化。

l :同时允许安全会话环境初始化和接受。

GSSContextInterface

该类的实例负责提供对等实体间的安全服务。客户端该类实例化的方法:

GSSContext GSSManager.createContext(GSSNamepeer,

Oid mech,

GSSCredential clientCreds,

int lifetime)

throws GSSException

该API返回一个初始化的安全环境,该环境链接了其要通信的对等实体,以及底层相应的安全机制。对等实体需要该客户端的credential用于认证。

服务器端实例化方法:

GSSContextGSSManager.createContext(GSSCredential serverCreds)

throws GSSException

该API返回一个用于接受的安全环境,在此时刻,该安全环境并不知道要与之连接的客户端名称以及底层所使用的安全机制。然而,一旦到来的请求不符合服务器的principal或者底层安全机制不相符的话,连接就会失败。

在GSSContext可以提供安全服务之前必须先在两个对等实体之间完成token的交换。每次调用GSSContext的establishment方法都会产生一个不透明的token,应用服务器必须将这个token传送给对等实体。

客户端使用下述API确立安全环境:

byte[]GSSContext.initSecContext(byte[] inToken,

int offset,

int len)

throws GSSException

服务器使用另一个API:

byte[]acceptSecContext(byte[] inToken,

int offset,

int len)

throws GSSException

这两个方法是补足的。一个方法的输出是另一个方法的输入。客户端第一次调用initSecContext的时候产生第一个token,最后一个token的产生依赖于选择的底层安全机制以及其属性设置。

GSS-APItoken来回传递的次数随底层安全机制的不同而不同,并且和安全机制单向认证还是双向认证相关。因此,客户端和服务器都要持续调用安全环境establishment方法,直到这个过程结束。

在底层安全机制为kerberos v5的情况下,安全环境的确立要经过多个步骤。首先客户端使用initSecContext方法生成一个token,并包含一个kerberos AP-REQ消息。为了建立这个消息,客户端使用自身的TGT请求一个serviceticket,该service ticket由服务器端长期密钥加密并封装到AP-REQ消息中。服务器收到这个token之后,把它传递到acceptSecContext方法中解密service ticket并认证客户端。如果不需要双向认证,此时安全环境确立成功,acceptSecContext方法不产生返回值。如果需要双向认证,上述方法会产生一个token,并封装到AP-REP消息中。这个消息会送到initSecContext方法中,之后双方安全环境确立成功。

注意GSSContext在客户端初始化的时候,它是明确底层的安全机制的,GSS-API框架会获得一个合适的安全机制的实例。之后,所有对GSSContext的请求都被安全机制的实例代理。在服务器端,直到客户端的第一个token到达之后,才确定底层安全机制。

下面是客户端和服务器的例子:

【Client】

classClientAction implements PrivilegedAction {

public Object run() {

...

...

try {

GSSManager manager = GSSManager.getInstance();

GSSName clientName =

manager.createName("duke", GSSName.NT_USER_NAME);

GSSCredential clientCreds =

manager.createCredential(clientName,

8*3600,

desiredMechs,

GSSCredential.INITIATE_ONLY);

GSSName peerName =

manager.createName("nfs@bar.foo.com",

GSSName.NT_HOSTBASED_SERVICE);

GSSContext secContext =

manager.createContext(peerName,

krb5Oid,

clientCreds,

GSSContext.DEFAULT_LIFETIME);

secContext.requestMutualAuth(true);

// The first input token is ignored

byte[] inToken = new byte[0];

byte[] outToken = null;

boolean established = false;

// Loop while the context is still not established

while (!established) {

outToken =

secContext.initSecContext(inToken, 0, inToken.length);

// Send a token to the peer if one was generated

if (outToken != null)

sendToken(outToken);

if (!secContext.isEstablished()) {

inToken = readToken();

else

established = true;

}

} catch (GSSException e) {

....

}

...

...

}

}

【Server】

classServerAction implelemts PrivilegedAction {

public Object run() {

...

...

try {

GSSManager manager = GSSManager.getInstance();

GSSName serverName =

manager.createName("nfs@bar.foo.com",

GSSName.NT_HOSTBASED_SERVICE);

GSSCredential serverCreds =

manager.createCredential(serverName,

GSSCredential.INDEFINITE_LIFETIME,

desiredMechs,

GSSCredential.ACCEPT_ONLY);

GSSContext secContext = manager.createContext(serverCreds);

byte[] inToken = null;

byte[] outToken = null;

// Loop while the context is still not established

while (!secContext.isEstablished()) {

inToken = readToken();

outToken =

secContext.acceptSecContext(inToken, 0, inToken.length);

// Send a token to the peer if one was generated

if (outToken != null)

sendToken(outToken);

}

} catch (GSSException e) {

...

}

...

...

}

}

MessageProtection

一旦安全环境确立之后,双方可以开始安全通信,Java GSS-API提供双方的消息完整性和机密性保障。下面两个方法实现这组功能:

byte[]GSSContext.wrap(byte[] clearText,

int offset,

int len,

MessageProp properties)

throws GSSException

byte[]unwrap(byte[] inToken,

int offset,

int len,

MessageProp properties)

throws GSSException

warp方法把要传递的明文消息封装到token中,因此保障了消息的完整性。作为可选项,消息可以被加密,通过制定一个properties对象。Wrap方法产生一个不透明的token并传送到对等实体端。Token传递到unwrap方法中,并被还原成明文。

CredentialDelegation

Java GSS-API允许客户端安全地请求服务器作为代理,这种情况下服务器就可以用客户端的身份初始化一个安全环境,如下图:

客户端在第一次调用initSecContext方法之前请求服务器作为代理:

voidGSSContext.requestCredDeleg(boolean state)

throws GSSException

在安全环境确立之后,服务器接收到客户端的代理请求:

GSSCredential GSSContext.getDelegCred()throws GSSException

此时服务器可以传递GSSCredential到GSSManager.createContext()方法中假扮客户端。

在kerberosv5安全机制下,代理credential是一个由第一次发送的token封装的forwardedTGT。使用这个TGT,服务器可以以客户端的身份获得其他任何服务的service ticket。

总结

Kerberos是一种安全并且高效的认证机制,使用Kerberos对分布式计算平台做安全认证,是个不错的选择。JAAS的可插卸式以及可堆叠的安全认证方式,以及Java GSS-API的实现,是把Kerberos从简单的使用到编程融入实际运行环境的有力助手。

参考文献

1. Neuman, Clifford and Tso, Theodore (1994).Kerberos: An Authentication Service for Computer Networks, IEEE Communications,volume 39 pages 33-38

2. J.Kohl and C.Neuman. The Kerberos NetworkAuthentication Service (V5) Internet Engineering Task Force, September 1993Request for Comments 1510

3. V. Samar and C. Lai. Making Login ServicesIndependent from Authentication Technologies. In Proceedings of the SunSoftDeveloper's Conference, March 1996.

4. X/Open Single Sign-On Service (XSSO) -Pluggable Authentication. Preliminary Specification P702, The Open Group, June1997. http://www.opengroup.org

6. J. Linn. Generic Security ServiceApplication Program Interface,Version 2. Internet Engineering Task Force,January 2000 Request for Comments 2743

7. J. Linn. The Kerberos Version 5 GSS-APIMechanism. Internet Engineering Task Force, June 1996 Request for Comments 1964

8. C.Adams. The Simple Public-Key GSS-APIMechanism (SPKM). Internet Engineering Task Force, October 1996 Request forComments 2025

9. J. Kabat and M.Upadhyay. Generic SecurityService API Version 2: Java Bindings. Internet Engineering Task Force, January1997 Request for Comments 2853

10. JavaTM 2 Platform, Standard Edition, v1.4 API Specification.http://java.sun.com/j2se/1.4/docs/api/overview-summary.html

转载地址:https://blog.csdn.net/linuxchyu/article/details/8038767 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Ubuntu12.04 更新源
下一篇:hadoop 2.0 详细配置教程

发表评论

最新留言

初次前来,多多关照!
[***.217.46.12]2024年04月26日 00时56分19秒