參考文獻:
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.