Kerberos认证流程
Last updated
Last updated
Kerberos协议由麻省理工学院开发,如今主要被用于Windows网络认证,Windows 2000和之后的操作系统使用Kerberos协议为其默认认证方法。加入Windows域则代表启动Kerberos作为客户端到服务端认证的默认协议,如果双方其一或全都未加入Windows域,则使用NTLM进行身份验证。
Kerberos协议认证过程中主要存在三种角色:
Client
,客户端,访问服务
Server
,服务端,提供服务
KDC
(Key Distribution Center),密钥分发中心
Kerberos协议的认证流程如下图所示:
Client
向KDC
的AS(Authentication Service)
服务发送KRB_AS_REQ
请求,目的是获得TGT
(Ticket Granting Ticket),发送的内容包括使用Client
用户哈希加密的时间戳,这也就是用户凭证。
这一步也叫做预认证,证明Client
有域内的用户和对应的哈希,可以进行下一阶段的请求。
抓包来看,KRB_AS_REQ
包含的字段如下:
pvno
,Kerberos协议版本号,现在常用的是Kerberos 5
msg-type
,消息类型,10
即0x0a
,代表krb-as-req
padata
,认证相关信息
req-body
,里面包含kdc-options
、cname
、sname
、till
、nonce
、etype
等
padata
即PA_DATA
,其中在KRB_AS_REQ
阶段时用到的主要是:
ENC_TIMESTAMP
,用户哈希加密的时间戳
PA_PAC_REQUEST
,启动PAC支持的扩展
在req-body
里,主要有:
kdc-options
,一些flag字段
cname
,发起请求的用户名
sname
,请求的服务名,在KRB_AS_REQ
中为krbtgt
realm
,域名
till
,到期时间
nonce
,随机生成的一个数
etype
,加密类型
KDC在收到KRB_AS_REQ
之后,使用发起请求的用户的哈希解密凭证得到时间戳,如果解密成功并且时间在一定范围内,则通过预认证。
预认证通过后,KDC
会返回TGT
票据,此票据是使用KDC
的krbtgt
用户的hash加密的,理论上无法被伪造和解密。
KRB_AS_REP
的主要字段有:
pvno
, 版本
msg-type
,消息类型
crealm
,域名
cname
,请求的用户名
ticket
,加密的票据
enc-part
,里面有下阶段的认证密钥
可以看到,在ticket
字段里,主要包含了域名、服务名、使用krbtgt
用户哈希加密的密文等。
而enc-part
里也是密文,但这里的密文是使用请求用户的哈希加密的,所以是可以解密的,里面是下一阶段的认证密钥。
通过预认证之后,Client
向KDC
的TGS(Ticket Granting Service)
服务发起请求,请求中包含了之前申请的TGT。
主要的字段和KRB_AS_REQ
相同,但内容有区别。
padata
字段里的ap-req
字段里的ticket
就是上面申请的TGT,而authenticator
是在KRB_AS_REP
中得到的下一阶段认证密钥。
req-body
里主要有这些字段:
kdc-options
,一些特殊选项,比如是否可转发等
cname
,请求的用户名
realm
,域名
sname
,需要申请访问的服务名,如cifs
等,如果服务是krbtgt
,那得到的ST(服务票据)是可以当做TGT来使用的
till
,到期时间
nonce
,随机数
KDC
验证TGT
票据和对应服务后,会返回ST
票据给Client
,这张票据对应着相关服务的访问权限,也就是俗称的白银票据。此票据是使用所请求的服务账户hash加密的,理论上也不可伪造和解密。
这些字段就不再解释,和之前步骤的大致相同,这里同样有enc-part
,它是使用前面KRB_AS_REP
阶段得到的key
字段加密的,解密后同样得到一个key
,作为下一阶段的认证密钥。
Client
请求访问对应的服务,提供ST和KRB_TGS_REP
阶段得到的认证密钥加密的字段,以获取访问权限。通过设置ap-options
的MUTUAL-REQUIRED
可以进行双向认证。
除非Client
要求进行双向认证,否则服务端一般不回复KRB_AP_REP
.
Kerberos协议支持S4U扩展,通过此扩展可以实现委派的功能。
这时流程中存在四个角色:
Client
,客户端
KDC
Service1
,代理用户请求的服务
Service2
,要被访问的服务
S4U
扩展有两个子协议:S4U2self
和S4U2proxy
,前者让Service1
代表用户获得对Service1
自身的票据,也就是获得了Client
对Service1
的票据;后者则允许Service1
代表用户去请求Service2
的服务权限。
这里要说明的是,委派功能并不完全等同于S4U
扩展,还能使用forwarded TGT的方法实现,流程如下图:
从上面可以看出,这种方式要求Client
要先通过Kerberos的方式进行认证,而S4U2self
可以让用户使用其他的验证方式来获得对Service1
的访问权限,这样就简化了整体流程,也扩展了适用场景。
使用S4U
扩展后,委派的流程如下:
Client
可以使用Kerberos以外的验证方式,来获得对Service1
的访问权限,这里Service1
并不需要得到Client
的相关凭据。
Service1
已经从KDC处得到了TGT,那么它会代表Client
去请求KDC,以获得自身可转发的ST.
可以看到padata
里多了pA-FOR-USER
,里面的KerberosString
字段表明Service1
是代表哪个用户进行请求的。
req-body
里能看到cname
和sname
都是Service1
,因为Service1
代替了Client
向KDC发起请求,请求的目标服务也是Service1
.
要想获得可转发的ST,需要满足:
使用的TGT是可转发的
Service1
配置了约束委派
请求时设置了可转发标志
Client
不是敏感账户
KDC返回对Service1
的可转发ST给Service1
这一步实际上没什么作用,因为单靠S4U2self
协议并不能请求到其他服务,这需要靠S4U2proxy
完成。
Client
向Service1
发起请求,需要Service1
以Client
的身份去访问Service2
,这里就要求Service1
通过前几个步骤来获得对自身的可转发ST.
Service1
代表Client
向KDC请求获得Service2
的ST,这个ST也应是可转发的,所以kdc-options
应设置forwardable
和cname-in-addl-tkt
,后者是为了标志S4U2proxy
功能。
与普通的KRB_TGS_REQ
一样,使用的TGT放在padata
中。这里的cname
是Client
,sname
为Service2
.
这次还多了一个Service1
的ST,放在了req-body
的additional-tickets
中。
如果上一步的请求中存在特权属性证书(PAC),那么KDC会验证PAC,在PAC有效或不存在PAC的情况下,返回Service2
的ST给Service1
。此ST中cname
和crealm
字段存储的是Client
的信息,不是Service1
的信息。
Service1
向Service2
发起请求,后者会将其看作是Client
,并且认为Client
已经通过了KDC验证。
Service2
响应Service1
Service1
响应用户