談談基于Kerberos的Windows Network Authentication[上篇]
Content:
基本原理
引入Key Distribution: KServer-Client從何而來
引入Authenticator : 為有效的證明自己提供證據
引入Ticket Granting Service:如何獲得Ticket
Kerberos的3個Sub-protocol:整個Authentication的流程
User2User Protocol: 有效地保障Server的安全
Kerberos的優點的優點
前幾天在給人解釋Windows是如何通過Kerberos進行Authentication的時候,講了半天也別把那位老兄講明白,還差點把自己給繞進去。后來想想原因有以下兩點:對于一個沒有完全不了解Kerberos的人來說,Kerberos的整個Authentication過程確實不好理解——一會兒以這個Key進行加密、一會兒又要以另一個Key進行加密,確實很容易把人給弄暈;另一方面是我講解方式有問題,一開始就從Kerberos的3個Sub-protocol全面講述整個Authentication 過程,對于一個完全不了解Kerberos的人來說要求也忒高了點。為此,我花了一些時間寫了這篇文章,盡量以由淺入深、層層深入的方式講述我所理解的基于Kerberos的Windows Network Authentication,希望這篇文章能幫助那些對Kerberos不明就里的人帶來一絲幫助。對于一些不對的地方,歡迎大家批評指正。
一、 基本原理
Authentication解決的是“如何證明某個人確確實實就是他或她所聲稱的那個人”的問題。對于如何進行Authentication,我們采用這樣的方法:如果一個秘密(secret)僅僅存在于A和B,那么有個人對B聲稱自己就是A,B通過讓A提供這個秘密來證明這個人就是他或她所聲稱的A。這個過程實際上涉及到3個重要的關于Authentication的方面:
-
Secret如何表示。
-
A如何向B提供Secret。
-
B如何識別Secret。
基于這3個方面,我們把Kerberos Authentication進行最大限度的簡化:整個過程涉及到Client和Server,他們之間的這個Secret我們用一個Key(KServer-Client)來表示。Client為了讓Server對自己進行有效的認證,向對方提供如下兩組信息:
-
代表Client自身Identity的信息,為了簡便,它以明文的形式傳遞。
-
將Client的Identity使用KServer-Client作為Public Key、并采用對稱加密算法進行加密。
由于KServer-Client僅僅被Client和Server知曉,所以被Client使用KServer-Client加密過的Client Identity只能被Client和Server解密。同理,Server接收到Client傳送的這兩組信息,先通過KServer-Client對后者進行解密,隨后將機密的數據同前者進行比較,如果完全一樣,則可以證明Client能過提供正確的KServer-Client,而這個世界上,僅僅只有真正的Client和自己知道KServer-Client,所以可以對方就是他所聲稱的那個人。

Keberos大體上就是按照這樣的一個原理來進行Authentication的。但是Kerberos遠比這個復雜,我將在后續的章節中不斷地擴充這個過程,知道Kerberos真實的認證過程。為了使讀者更加容易理解后續的部分,在這里我們先給出兩個重要的概念:
-
Long-term Key/Master Key:在Security的領域中,有的Key可能長期內保持不變,比如你在密碼,可能幾年都不曾改變,這樣的Key、以及由此派生的Key被稱為Long-term Key。對于Long-term Key的使用有這樣的原則:被Long-term Key加密的數據不應該在網絡上傳輸。原因很簡單,一旦這些被Long-term Key加密的數據包被惡意的網絡監聽者截獲,在原則上,只要有充足的時間,他是可以通過計算獲得你用于加密的Long-term Key的——任何加密算法都不可能做到絕對保密。
在一般情況下,對于一個Account來說,密碼往往僅僅限于該Account的所有者知曉,甚至對于任何Domain的Administrator,密碼仍然應該是保密的。但是密碼卻又是證明身份的憑據,所以必須通過基于你密碼的派生的信息來證明用戶的真實身份,在這種情況下,一般將你的密碼進行Hash運算得到一個Hash code, 我們一般管這樣的Hash Code叫做Master Key。由于Hash Algorithm是不可逆的,同時保證密碼和Master Key是一一對應的,這樣既保證了你密碼的保密性,有同時保證你的Master Key和密碼本身在證明你身份的時候具有相同的效力。
-
Short-term Key/Session Key:由于被Long-term Key加密的數據包不能用于網絡傳送,所以我們使用另一種Short-term Key來加密需要進行網絡傳輸的數據。由于這種Key只在一段時間內有效,即使被加密的數據包被黑客截獲,等他把Key計算出來的時候,這個Key早就已經過期了。
二、引入Key Distribution: KServer-Client從何而來
上面我們討論了Kerberos Authentication的基本原理:通過讓被認證的一方提供一個僅限于他和認證方知曉的Key來鑒定對方的真實身份。而被這個Key加密的數據包需要在Client和Server之間傳送,所以這個Key不能是一個Long-term Key,而只可能是Short-term Key,這個可以僅僅在Client和Server的一個Session中有效,所以我們稱這個Key為Client和Server之間的Session Key(SServer-Client)。
現在我們來討論Client和Server如何得到這個SServer-Client。在這里我們要引入一個重要的角色:Kerberos Distribution Center-KDC。KDC在整個Kerberos Authentication中作為Client和Server共同信任的第三方起著重要的作用,而Kerberos的認證過程就是通過這3方協作完成。順便說一下,Kerberos起源于希臘神話,是一支守護著冥界長著3個頭顱的神犬,在keberos Authentication中,Kerberos的3個頭顱代表中認證過程中涉及的3方:Client、Server和KDC。
對于一個Windows Domain來說,Domain Controller扮演著KDC的角色。KDC維護著一個存儲著該Domain中所有帳戶的Account Database(一般地,這個Account Database由AD來維護),也就是說,他知道屬于每個Account的名稱和派生于該Account Password的Master Key。而用于Client和Server相互認證的SServer-Client就是有KDC分發。下面我們來看看KDC分發SServer-Client的過程。
通過下圖我們可以看到KDC分發SServer-Client的簡單的過程:首先Client向KDC發送一個對SServer-Client的申請。這個申請的內容可以簡單概括為“我是某個Client,我需要一個Session Key用于訪問某個Server ”。KDC在接收到這個請求的時候,生成一個Session Key,為了保證這個Session Key僅僅限于發送請求的Client和他希望訪問的Server知曉,KDC會為這個Session Key生成兩個Copy,分別被Client和Server使用。然后從Account database中提取Client和Server的Master Key分別對這兩個Copy進行對稱加密。對于后者,和Session Key一起被加密的還包含關于Client的一些信息。
KDC現在有了兩個分別被Client和Server 的Master Key加密過的Session Key,這兩個Session Key如何分別被Client和Server獲得呢?也許你 馬上會說,KDC直接將這兩個加密過的包發送給Client和Server不就可以了嗎,但是如果這樣做,對于Server來說會出現下面 兩個問題:
-
由于一個Server會面對若干不同的Client, 而每個Client都具有一個不同的Session Key。那么Server就會為所有的Client維護這樣一個Session Key的列表,這樣做對于Server來說是比較麻煩而低效的。
-
由于網絡傳輸的不確定性,可能出現這樣一種情況:Client很快獲得Session Key,并將這個Session Key作為Credential隨同訪問請求發送到Server,但是用于Server的Session Key確還沒有收到,并且很有可能承載這個Session Key的永遠也到不了Server端,Client將永遠得不到認證。
為了解決這個問題,Kerberos的做法很簡單,將這兩個被加密的Copy一并發送給Client,屬于Server的那份由Client發送給Server。

可能有人會問,KDC并沒有真正去認證這個發送請求的Client是否真的就是那個他所聲稱的那個人,就把Session Key發送給他,會不會有什么問題?如果另一個人(比如Client B)聲稱自己是Client A,他同樣會得到Client A和Server的Session Key,這會不會有什么問題?實際上不存在問題,因為Client B聲稱自己是Client A,KDC就會使用Client A的Password派生的Master Key對Session Key進行加密,所以真正知道Client A 的Password的一方才會通過解密獲得Session Key。
三、引入Authenticator - 為有效的證明自己提供證據
通過上面的過程,Client實際上獲得了兩組信息:一個通過自己Master Key加密的Session Key,另一個被Sever的Master Key加密的數據包,包含Session Key和關于自己的一些確認信息。通過第一節,我們說只要通過一個雙方知曉的Key就可以對對方進行有效的認證,但是在一個網絡的環境中,這種簡單的做法是具有安全漏洞,為此,Client需要提供更多的證明信息,我們把這種證明信息稱為Authenticator,在Kerberos的Authenticator實際上就是關于Client的一些信息和當前時間的一個Timestamp(關于這個安全漏洞和Timestamp的作用,我將在后面解釋)。
在這個基礎上,我們再來看看Server如何對Client進行認證:Client通過自己的Master Key對KDC加密的Session Key進行解密從而獲得Session Key,隨后創建Authenticator(Client Info + Timestamp)并用Session Key對其加密。最后連同從KDC獲得的、被Server的Master Key加密過的數據包(Client Info + Session Key)一并發送到Server端。我們把通過Server的Master Key加密過的數據包稱為Session Ticket。
當Server接收到這兩組數據后,先使用他自己的Master Key對Session Ticket進行解密,從而獲得Session Key。隨后使用該Session Key解密Authenticator,通過比較Authenticator中的Client Info和Session Ticket中的Client Info從而實現對Client的認證。

為什么要使用Timestamp?
到這里,很多人可能認為這樣的認證過程天衣無縫:只有當Client提供正確的Session Key方能得到Server的認證。但是在現實環境中,這存在很大的安全漏洞。
我們試想這樣的現象:Client向Server發送的數據包被某個惡意網絡監聽者截獲,該監聽者隨后將數據包座位自己的Credential冒充該Client對Server進行訪問,在這種情況下,依然可以很順利地獲得Server的成功認證。為了解決這個問題,Client在Authenticator中會加入一個當前時間的Timestamp。
在Server對Authenticator中的Client Info和Session Ticket中的Client Info進行比較之前,會先提取Authenticator中的Timestamp,并同當前的時間進行比較,如果他們之間的偏差超出一個可以接受的時間范圍(一般是5mins),Server會直接拒絕該Client的請求。在這里需要知道的是,Server維護著一個列表,這個列表記錄著在這個可接受的時間范圍內所有進行認證的Client和認證的時間。對于時間偏差在這個可接受的范圍中的Client,Server會從這個這個列表中獲得最近一個該Client的認證時間,只有當Authenticator中的Timestamp晚于通過一個Client的最近的認證時間的情況下,Server采用進行后續的認證流程。
Time Synchronization的重要性
上述 基于Timestamp的認證機制只有在Client和Server端的時間保持同步的情況才有意義。所以保持Time Synchronization在整個認證過程中顯得尤為重要。在一個Domain中,一般通過訪問同一個Time Service獲得當前時間的方式來實現時間的同步。
雙向認證(Mutual Authentication)
Kerberos一個重要的優勢在于它能夠提供雙向認證:不但Server可以對Client 進行認證,Client也能對Server進行認證。
具體過程是這樣的,如果Client需要對他訪問的Server進行認證,會在它向Server發送的Credential中設置一個是否需要認證的Flag。Server在對Client認證成功之后,會把Authenticator中的Timestamp提出出來,通過Session Key進行加密,當Client接收到并使用Session Key進行解密之后,如果確認Timestamp和原來的完全一致,那么他可以認定Server正式他試圖訪問的Server。
那么為什么Server不直接把通過Session Key進行加密的Authenticator原樣發送給Client,而要把Timestamp提取出來加密發送給Client呢?原因在于防止惡意的監聽者通過獲取的Client發送的Authenticator冒充Server獲得Client的認證。
談談基于Kerberos的Windows Network Authentication - Part II
相關內容:
[原創]談談基于Kerberos的Windows Network Authentication - Part I
[原創]談談基于Kerberos的Windows Network Authentication - Part II
[原創]談談基于Kerberos的Windows Network Authentication - Part III


前幾天在給人解釋Windows是如何通過Kerberos進行Authentication的時候,講了半天也別把那位老兄講明白,還差點把自己給繞進去。后來想想原因有以下兩點:對于一個沒有完全不了解Kerberos的人來說,Kerberos的整個Authentication過程確實不好理解——一會兒以這個Key進行加密、一會兒又要以另一個Key進行加密,確實很容易把人給弄暈;另一方面是我講解方式有問題,一開始就從Kerberos的3個Sub-protocol全面講述整個Authentication 過程,對于一個完全不了解Kerberos的人來說要求也忒高了點。為此,我花了一些時間寫了這篇文章,盡量以由淺入深、層層深入的方式講述我所理解的基于Kerberos的Windows Network Authentication,希望這篇文章能幫助那些對Kerberos不明就里的人帶來一絲幫助。對于一些不對的地方
浙公網安備 33010602011771號