参考文献:
How the Kerberos Version 5 Authentication Protocol Works: Logon and Authentication
SQL Server配置delegation实现double-hop
前言
之前写过两篇关于kerberos的博客,但是对于kerberos的验证过程还不够透彻,现在来详细讲解kerberos的验证过程。
1.Kerberos Exchange and Message Summary
常见的windows验证有NTLM和kerberos两种,而本文的主题就是讲解kerberos连接过程。kerberos的名字起源来自于希腊神话中的一头看门的三头犬。所以kerberos验证也就有三个参与者, 分别是Client、Server和KDC。其中信息交互如下图所示:
如上图所示,kerberos验证一共分为六步,这六步每两步可以分为一个阶段,下面将详细介绍这三个阶段的六步信息交互过程。这里需要注意的是,在KDC中有两个服务,分别是Authentication Service(简称AS)和Ticket-Granting Service(简称TGS),而这个KDC又是在Domain Controller(简称DC)中的。
1.1.The Authentication Service(简称AS) Exchange
1.1.1. Kerberos authentication service request (KRB_AS_REQ),kerberos验证服务请求
The client contacts the Key Distribution Center's authentication service for a short-lived ticket (a message containing the client's identity and—for Windows clients—SIDs) called a ticket-granting ticket (TGT). This happens at logon.
这个阶段发生在用域账户登陆的时候,在登陆成功以后会自动将自身的明文用户名发送给AS,请求TGT。用户在logon的时候会输入用户名与密码,密码将以hash的形式保存在本地缓存中,并以此作为Client端的user key。
1.1.2. Kerberos authentication service response (KRB_AS_REP)
The authentication service (AS) constructs the TGT and creates a session key the client can use to encrypt communication with the ticket-granting service (TGS). The TGT has a limited lifetime. At the point that the client has received the TGT, the client has not been granted access to any resources, even to resources on the local computer.
AS在收到Client发送过来的用户名以后,会用这个用户名去自身的account database中查找是否存在这个域账户,如果域账户存在,那么就找出这个账户所对应的密码,注意这里的密码也是密码的hash,在windows系统中,不论是本机还是DC中,都不会保存明文密码,而只保存密码的hash。我们在account database中得到了用户的密码hash值以后,以此作为KDC端的user key。
值得一提的是,Server端在启动的时候,也会在本地会保存自身的service key,KDC上会找到这个Server所对应的service key。
KDC上除了user key 跟 service key以外,还有TGS自身的key,我们称它为TGS key。然后AS在接到客户端的TGT申请请求,并且验证用户通过以后,会创建一个连接Client和TGS的会话keyClient/TGS Session Key以及TGT。AS将TGT用TGS key加密,我们称这个信息为MessageA,将Client/TGS Session Key用AS端的user key加密,我们称这个信息为MessageB。将MessageA和MessageB发送给客户端。
Why use a TGT? Could the AS simply issue a ticket for the target server? Yes, but if the AS issued tickets directly, the user would have to enter a password for every new server/service connection. Issuing a TGT with a short lifespan (typically 10 hours) gives the user a valid ticket for the ticket-granting service, which in turn issues target-server tickets. The TGT's main benefit is that the user only has to enter a password once, at logon.
前面说了这么多,那么我们有疑问了,为什么要使用TGT呢?为什么不直接给Client一个连接Server的Service Ticket就好了呢?这是因为,如果直接给客户端一个连接具体Server的Service Ticket的话,那么每当要连接新的Service的时候,我们又要重新输入一次用户名与密码用于建立新服务的连接。但是假如我们使用TGT的话,那么在TGT过期(expire)之前,都不需要重新输入密码。一般TGT的失效过期时间是10小时。
1.1.3总结:
在用户logon成功以后,Client、Server和KDC应该有如下这些key,其中KDC中的Client-Ticket-Granting Service Session Key(简称Client/TGS Session Key)是后来加的,在原文中并没有。但是在原文中提到了Client/TGS Session Key是由Client跟KDC共享的。而且Client/TGS Session Key也是AS发给Client的,所以我就在KDC上加了这个Key。
之前的说法是错误的,在KDC中不需要保存Session key,这是因为KDC在创建session key的时候,会将一个session key的宝贝跟TGT打包组合在一起再用TGS Key来加密。所以在后面的过程中,当TGS收到TGT的时候,KDC只需要打开这个包就得到了session key了。后面的service ticket也会跟一个session key一同打包发送给client。然后再server端解密以后被server端得到用来解密authenticator。
The KDC replies with KRB_AS_REP containing a service ticket for itself. This special service ticket is called a ticket-granting ticket (TGT). Like an ordinary service ticket, a TGT contains a copy of the session key that the service (in this case the KDC) will use in communicating with the user. The message that returns the TGT to the user also includes a copy of the session key that the user can use in communicating with the KDC. The TGT is encrypted in the KDC's long-term key. The user's copy of the session key is encrypted in the user's long-term key.
1.2The Ticket-Granting Service Exchange
1.2.1. Kerberos ticket-granting service request (KRB_TGS_REQ)
Client在可得被TGS Key加密的TGT(MessageA)以及被AS端的user key加密的Client/TGS Session Key(MessageB)以后,就可以开始申请相应服务的连接了。这里需要注意的一点是,我们可以发现TGT是被TGS Key加密的,所以Client端打不开TGT中的内容。
首先我们要用Client的user key解密MessageB得到Client/TGS Session Key,然后Client端想TGS端发出Service Ticket申请,它会把以下内容发送给TGS:
- SPN(Message C):全称是Service Principal Name,这个在第一次发送的时候是明文的,后面再次发送的时候就是密文了。这一点我们可以通过SSPIClient这个工具验证。在SSPIClient的log文件中,有多个InitializeSecurityContextA,但是只有一个InitializeSecurityContextA中的pszTargetName是含有明文SPN的,比如pszTargetName= 'MSSQLSvc/SANZ-W7.msft.com:1433',其他地方的pszTargetName都是等于'<NULL>'。
- 被Client/TGS Session Key加密的Authenticator(MessageD)。
- 被TGS Key加密的TGT(MessageA),这个是在第2步中AS发送给Client端的。
整个过程如下图所示:
The client wants access to local and network resources. To gain access, the client sends a request to the TGS for a ticket for the local computer or some network server or service. This ticket is referred to as the service ticket or session ticket. To get the ticket, the client presents the TGT, an authenticator, and the name of the target server (the Server Principal Name or SPN).
1.2.2. Kerberos ticket-granting service response (KRB_TGS_REP)
TGS在收到Client端发送过来的内容以后,会对之一一解密。首先使用TGS Key解密TGT,然后使用Client/TGS Session Key解密Authenticator,SPN在这里是明文的,所以此处不用解密。在解密Authenticator以后,对evaluates(评估)这个Authenticator,如果通过测试,则会创建一个Client/Server Session Key用于建立Client和Server之间的会话,然后再创建Client/Server Session Key的一个拷贝,这两个相同的Session Key有不同的用处。
首先TGS将其中的一个Client/Server Session Key使用Client/TGS Session Key加密,形成MessageE,然后将另外一个Client/Server Session Key和一个 Ticket以及Client端的用户验证信息(User Credential)打包组合组着在一起,再用TGS端的Service Key加密,形成MessageF。TGS将MessageE和MessageF传送给Client。具体过程如下图所示:
When the KDC receives KRB_TGS_REQ, it decrypts the TGT with its own secret key, extracting the user's TGS session key (logon session key). It uses the session key to decrypt the authenticator and evaluates that. If the authenticator passes the test, the KDC extracts the user's authorization data from the TGT and creates another session key for the client to use with the service. The KDC encrypts one copy of this new session key with the user's TGS session key. It embeds another copy of the session key in a ticket, along with the user's authorization data, and encrypts the ticket with the service's key. The KDC then sends these credentials back to the client in a Kerberos ticket-granting service reply (KRB_TGS_REP).
The TGS examines the TGT and the authenticator. If these are acceptable, the TGS creates a service ticket. The client's identity is taken from the TGT and copied to the service ticket. Then the ticket is sent to the client.
Note
- The TGS cannot determine if the user will be able to get access to the target server. It simply returns a valid ticket. Authentication does not imply authorization.
1.3The Client/Server Exchange
5. Kerberos application server request (KRB_AP_REQ)
客户端在得到TGS传送过来的用Client/TGS Session Key加密的Client/Server Session Key(MessageE)和用TGS端Service Key加密的Service Ticket(MessageF)以后,首先解密Client/Server Session Key,并将它保存在本地换粗中。然后创建一个新的由Client/Server Session Key加密的Authenticator(MessageG),将它和Service Ticket(MessageF)也就是MessageF传送给Server端。整个过程如下图所示:
KRB_AP_REQ Message Contents
After the client has the service ticket, the client sends the ticket and a new authenticator to the target server, requesting access. The server will decrypt the ticket, validate the authenticator, and for Windows services, create an access token for the user based on the SIDs in the ticket.
6. Kerberos application server response (optional) (KRB_AP_REP)
在Server端收到Client端发送过来的由Service Key加密的Service Ticket(MessageF)和由Client/Server Session Key加密的Authenticator(MessageG)以后,首先使用自身的Service Key解密Service Ticket,得到用户验证信息(User Credential)以及在TGS上与之一起打包的Client/Server Session Key。我们使用这个Client/Server Session Key解密Authenticator,如果Authenticator通过,那么向客户端发送一个由Client/Server Session Key加密的mutual authentication information给客户端。客户端在收到Server端发送过来的Mutual Authentication Information以后,用Client/Server Session Key解密,对比之前发送给Server的Authenticator,如果timestamp是正确的,那么证明这个连接是真实可信,到此连接建立。具体的过程如下图所示:
Optionally, the client might request that the target server verify its own identity. This is called mutual authentication. If mutual authentication is requested, the target server will take the client computer's timestamp from the authenticator, encrypt it with the session key the TGS provided for client-target server messages, and send it to the client.
Why is an authenticator necessary?
前面有两处地方提到了Authenticator,一处是KRB_TGS_REQ,另外一处是KRB_AP_REQ。这两个信息分别是客户端发送给TGS和Server端的。那么为什么需要Authenticator呢?以Server端来说,它相信从客户端传送过来的Service Ticket,因为这个Service Ticket是用Server端的service key加密的。但是Server不能确保这个Service Ticket是从可信的Client端发送过来的。传送到Server端的信息可能在之前被别人截取并且修改了信息再发送过来的。所以Server端要验证Client的信息。Server端在使用service key打开Service ticket以后得到了Session key,用这个Session key再去打开authenticator的信息,如果里面的authenticator data通过了验证,那么才表明这个client是可信的。
The target server can trust the contents of the ticket because the ticket is encrypted with the target server's secret key. However, the target server cannot trust that the ticket was really sent by the client specified in the ticket. The ticket could have been stolen and is now being included in an imposter's message.