A guided tour of Kerberos: Tutorial

爲了更好的理解 Kerberos 中的概念和認證的大體流程,這篇文檔是快速瞭解 Kerberos 的一篇非常棒的指南教程,原文地址爲 KERBEROS PROTOCOL TUTORIAL,也可以直接訪問原文地址查看。

This tutorial was written by Fulvio Ricciardi and is reprinted here with his permission. Mr. Ricciardi works at the National Institute of Nuclear Physics in Lecce, Italy. He is also the author of the Linux project zeroshell.net, where he originally published this tutorial. Thank you, Mr. Ricciardi!

本教程由 Fulvio Ricciardi 撰寫,並由它的許可在這裏轉載。Ricciardi 先生在意大利萊切(Lecce, Italy)國家核物理研究所工作,他還是 Linux 項目 zeroshell.net 的作者,他最初在該項目上發佈了本文,Thank you, Mr. Ricciardi!

Document version:	1.0.3    (11/27/2007)
Author:	Fulvio Ricciardi ([email protected])
INFN - the National Institute of Nuclear Physics
Computing and Network Services - LECCE, Italy

文檔版本: 1.0.3    (2007-11-27)
作者:Fulvio Ricciardi ([email protected])
     INFN - 國家核物理計算與網絡服務研究所-意大利萊切

1 介紹

Kerberos 協議目標是在開放和不安全的網絡(open and insecure networks)上提供可靠的身份驗證,其中屬於該協議的主機之間的通信可能會被攔截。但是請注意,如果使用的計算機容易受到攻擊則 Kerberos 不提供任何保證:身份驗證服務、應用程序服務(imap, pop, smtp, telnet, ftp, ssh , AFS, lpr, …) 和客戶端必須保持不斷更新以確保請求用戶和服務提供者的真實性。

以上幾點說明了這一句話:“Kerberos是用於不受信任網絡上的受信任主機的身份驗證協議”,舉例說明一下並重申一下這一概念:如果獲得對服務器的特權訪問的人可以複製包含密鑰的文件,則 Kerberos 的策略就沒有用。確實入侵者會將此密鑰放在另一臺計算機上,並且只需要爲該服務器獲得一個簡單的欺騙 DNS 或 IP 地址即可將其顯示爲真實的服務器。

2 目的

在描述組成 Kerberos 身份驗證系統的元素並查看其操作之前,下面列出了協議希望實現的一些目標:

  • 用戶的密碼絕不能通過網絡傳播;
  • 用戶密碼絕不能以任何形式存儲在客戶端計算機上:使用後必須立即丟棄;
  • 用戶密碼永遠不要以未加密的形式存儲在身份驗證服務數據庫(authentication server database)中;
  • 要求用戶在每個工作會話中僅輸入一次密碼,因此用戶可以透明地訪問其授權使用的所有服務,而不必在此會話期間重新輸入密碼。此特徵稱爲單點登錄(Single Sign-On)。
  • 認證信息管理是集中式的且位於認證服務器上。應用程序服務不得包含其用戶的身份驗證信息,這對於獲得以下結果至關重要:
    1. 管理員可以通過在單個位置執行操作來禁用任何用戶的帳戶,而不必在提供各種服務的多個應用程序服務上執行操作;
    2. 用戶更改密碼時,同時更改所有服務的密碼;
    3. 沒有身份驗證信息的冗餘,否則這些冗餘信息必須在各個地方得到保護;
  • 用戶不僅必須證明自己是誰,而且在被請求時,應用程序服務還必須向客戶端證明其真實性,此特性稱爲相互認證(Mutual authentication)。
  • 完成身份驗證和授權後,如果需要客戶端和服務器必須能夠建立加密連接。爲此 Kerberos 提供了對用於加密數據的加密密鑰的生成和交換的支持。

3 組件和術語的定義

此部分提供了對象和術語的定義,其知識對於隨後的 Kerberos 協議描述至關重要。由於許多定義是基於其他定義的,因此作者儘可能嘗試將它們排序,以便在定義術語時不提前給出術語的定義。但是,可能需要閱讀本節兩次(twice)才能完全理解所有術語。

3.1 領域(Realm)

術語 Realm 表示認證管理域,其目的是建立一個邊界,在該邊界內身份驗證服務有權對用戶、主機或服務進行身份驗證。 這並不意味着用戶和服務之間的認證必須屬於同一 realm:如果兩個對象是不同 Realm 的一部分,並且它們之間存在信任關係,則可以進行認證。這種特性將在下文描述爲交叉認證(Cross-Authentication)。

基本上 user/service 僅在其與該 realm 的身份驗證服務共享祕密(密碼/密鑰)時才屬於該 realm。

realm 的名稱區分大小寫,即大寫和小寫字母之間有區別,但通常情況下 realm 始終以大寫字母出現。在組織中使 realm 名稱與 DNS域相同(也是大寫字母)也是一種好習慣。 在選擇 realm 名稱時遵循這些提示可以大大簡化 Kerberos 客戶端的配置,尤其是在需要與子域(subdomains)建立信任關係時。 舉例來說,如果組織屬於 DNS 域 example.com,則相關 Kerberos 的 realm 最好是 EXAMPLE.COM

3.2 主體(Principal)

委託人是用於引用身份驗證服務數據庫中條目的名稱,principal 與給定 realm 的每個用戶、主機或服務相關聯。 Kerberos 5 中的主體具有以下類型:

component1/component2/.../componentN@REALM

但是實際上最多使用兩個組件,對於引用用戶的條目 principal 是以下類型:

Name[/Instance]@REALM

該實例是可選的且通常用於更好地限定用戶類型,例如管理員用戶通常具有admin實例。以下是引用給用戶的 principals 的示例:

[email protected]    admin/[email protected]    pluto/[email protected]

相反如果條目引用服務,則主體採用以下形式:

Service/Hostname@REALM

第一個組件是服務的名稱,例如 imap、AFS、ftp。通常 “主機” 一詞用於表示對計算機(telnet,rsh,ssh)的一般訪問。第二部分是提供所請求服務的計算機的完整主機名(FQDN),重要的是,此組件必須與應用程序服務器 IP 地址的 DNS 反向解析完全匹配(用小寫字母表示)。以下是引用服務的 principals 的有效示例:

imap/[email protected]
host/[email protected]
afs/[email protected]

應該注意的是最後一種情況是一個例外,因爲第二個組件不是主機名,而是主體所指的 AFS cell 的名稱。 最後有些 principals 不涉及用戶或服務,但在身份驗證系統的操作中起作用。一個整體示例是 krbtgt/REALM@REALM 及其關聯的密鑰,用於加密票據授予票據(我們將在後面介紹)。

在 Kerberos 4 中組件最多不能超過兩個,它們之間用字符.分隔而不是/,而引用服務的 principals 中的主機名是簡稱即不是 FQDN。以下是有效的示例:

[email protected]    [email protected]    [email protected]

3.3 票據(Ticket)

ticket 是客戶端提供給應用程序服務器以證明其身份真實性的東西,ticket 是由身份驗證服務器發行的,並使用其預定服務的密鑰進行加密。由於此密鑰是僅在身份驗證服務器和提供服務的服務器之間共享的祕密,因此即使請求 ticket 的客戶端也無法知道它或更改其內容,ticket 中包含的主要信息包括:

  • 請求用戶的 principal(通常是用戶名);
  • principal 服務的目的;
  • 可以使用 ticket 的客戶端計算機的 IP 地址,在 Kerberos 5 中此字段是可選的,也可以是多個字段,以便能夠在 NAT 或多宿主下運行客戶端。
  • ticket 有效期開始的日期和時間(以時間戳格式);
  • ticket 的最大壽命
  • 會話密鑰(其基本作用如下所述);

每個 ticket 都有一個有效期(通常爲10小時),這是必不可少的,因爲身份驗證服務器不再對已發出的 ticket 具有任何控制權,即使 realm 管理員可以隨時阻止某個用戶發佈新 ticket,也不能阻止用戶使用他們已經擁有的 ticket,限制 ticket 壽命的原因是爲了限制隨時間的濫用。

ticket 包含許多其他信息和標誌,這些信息和標誌描述了他們的行爲,但我們在這裏不做介紹。在瞭解身份驗證系統的工作原理之後,我們將再次討論 ticket 和 標誌。

3.4 加密(Encryption)

如您所見 Kerberos 通常需要對在身份驗證的各個參與者之間傳遞的消息(ticket 和身份驗證)進行加密和解密。重要的是要注意 Kerberos 僅使用對稱密鑰加密(換句話說相同的密鑰用於加密和解密)。某些項目(例如 pkinit)正在積極引入公鑰系統,以便通過呈現與經認證的公鑰相對應的私鑰來獲得初始用戶身份驗證,但是由於目前尚無標準,因此我們暫時跳過此討論。

3.4.1 加密類型

Kerberos 4 實現了一種加密類型即56位 DES,這種加密的弱點以及其他協議漏洞已使 Kerberos 4 過時了。但是 Kerberos 版本5 不能確定支持的加密方法的 number 或類型。支持並最佳地協商各種類型的加密是每個特定實現版本的任務,但是協議的這種靈活性和可擴展性加劇了 Kerberos 5 各種實現之間的互操作性問題。爲了讓用了不同實現的客戶端以及應用程序和身份驗證服務器能夠互操作,它們必須至少具有一種共同的加密類型。與 Kerberos 5 的 Unix 實現和 Windows Active Directory 中存在的實現之間的互操作性相關的困難就是一個典型的例子。實際上 Windows Active Directory 支持有限數量的加密,並且與 Unix 一樣僅具有 56位的 DES。儘管必須保證互操作性,但是儘管衆所周知的風險也要求使後者保持啓用狀態。隨後使用 MIT Kerberos 5 的 1.3 版本解決了該問題,此版本引入了 RC4-HMAC 支持,該支持也存在於 Windows 中,並且比 DES 更安全。在受支持的加密中(但不是 Windows),值得一提的是三重 DES(3DES)以及較新的 AES128 和 AES256。

3.4.2 加密密鑰(Encryption key)

如上所述 Kerberos 協議的目的之一是防止用戶密碼以未加密的形式存儲,甚至在身份驗證服務器數據庫中也是如此。考慮到每種加密算法都使用其自己的密鑰長度,很明顯如果不強迫用戶爲支持的每種加密方法使用固定大小的不同密碼,則加密 key 不能是密碼。 由於這些原因引入了 string2key 函數,該函數將未加密的密碼轉換爲適合於要使用的加密類型的加密密鑰。每次用戶更改密碼或輸入密碼進行身份驗證時都會調用此方法。string2key 稱爲哈希函數,這意味着它是不可逆的:鑑於加密密鑰無法確定生成該密鑰的密碼(除非通過暴力),著名的哈希算法是 MD5 和 CRC32。

3.4.3 鹽(Salt)

與版本4不同在 Kerberos 5 中引入了密碼鹽的概念。 這是在應用 string2key 函數獲取密鑰之前要與未加密密碼連接的字符串。Kerberos 5 使用與 salt 相同的 principal 用戶:

Kpippo = string2key(Ppippo + "[email protected]")

Kpippo 是用戶 pippo 的加密密鑰,而 Ppippo 是用戶的未加密密碼。這種鹽具有以下優點:

  • 屬於同一 realm 並且具有相同的未加密密碼的兩個 principals 仍然具有不同的密鑰。 例如假設有一個管理員負責日常工作([email protected])且一個負責管理工作(pippo/[email protected]),爲方便起見,此用戶很可能爲兩個 principals 設置了相同的密碼,鹽的存在保證了相關密鑰是不同的。
  • 如果用戶在不同的 realm 中有兩個帳戶,則經常會出現兩個 realm 的未加密密碼相同的情況,由於鹽的存在,一個 realm 中一個帳戶的可能破壞不會自動導致另一個 realm 被妥協。

可以配置一個 null 鹽來與 Kerberos 4 兼容,反之亦然,爲了與 AFS 兼容可以配置一個鹽,它不是 principal 的完整名稱,而僅僅是 cell 的名稱。

在討論了加密類型、string2key 和 salt 的概念之後,可以檢查以下觀察的準確性:爲了使各種 Kerberos 實現之間具有互操作性,僅協商一種通用的加密類型是不夠的,但是同樣也需要使用相同類型的 string2key 和 salt。

還需要注意的是,在解釋 string2key 和 salt 的概念時僅引用了用戶 principals 而沒有引用服務器的 principals,原因很明顯:即使服務與身份驗證服務器共享祕密,它也不是未加密的密碼(誰會輸入它呢?),而是由管理員在 Kerberos 服務器上生成的密鑰,其存儲爲它所提供服務的服務器上。

3.4.4 key 版本號 - kvno (Key Version Number)

當用戶更改密碼或管理員更新應用程序服務器的密鑰時,此更改將通過增加計數器來記錄,標識密鑰版本的計數器的當前值稱爲密鑰版本號或更簡稱爲 kvno

3.5 密鑰分發中心 - KDC(Key Distribution Center)

我們已經談到認證服務器,由於它是用戶和服務認證中涉及的基本對象,因此我們現在將對其進行更深入的研究,但不涉及其操作的所有細節,而將其作爲協議操作部分的主題。

Kerberos 環境中的身份驗證服務器基於其用於訪問服務的 ticket 分發功能,被稱爲密鑰分發中心,或更簡稱爲 KDC。由於它完全駐留在單個物理服務器上(它通常與單個進程重合),因此可以從邏輯上將其分爲三個部分:數據庫、身份驗證服務器(AS)和 票證授予服務器(TGS),讓我們簡單地看一下它們。

注意:可以使服務器在 Master/Slave(MIT 和 Heimdal)或多主控結構(Windows Active Directory)中的 realm 內爲冗餘。協議沒有描述如何獲得冗餘,而是取決於所使用的實現方式,在此將不進行討論。

3.5.1 數據庫(Database)

數據庫是與用戶和服務關聯的條目(entries)的容器,即使經常使用術語 principal 作爲條目的同義詞,我們也使用 principal(即條目的名稱)來引用條目,每個條目包含以下信息:

  • 條目所關聯的 principal;
  • 加密密鑰和相關的 kvno;
  • 與 principal 關聯的 ticket 的最大有效期;
  • 可以更新與 principal 相關聯的 ticket 的最長時間(僅 Kerberos 5);
  • 表徵 ticket 行爲的屬性或標誌;
  • 密碼到期日期;
  • principal 的到期日,之後將不發行 ticket。

爲了使竊取數據庫中存在的密鑰更加困難,實現中使用與主 K/M@REALM 關聯的主密鑰(master key)對數據庫進行加密。 即使是任何數據庫轉儲、用作備份或從 KDC 主服務器向從屬服務器傳輸也都使用此密鑰進行加密,爲了重新加載它們必須知道該密鑰。

3.5.2 身份認證服務 - AS(Authentication Server)

身份驗證服務器是 KDC 的一部分,當尚未經過身份驗證的用戶必須輸入密碼時它會響應來自客戶端的初始身份驗證請求。響應於身份驗證請求,AS發出一個特殊的 ticket,稱爲票證授予票據(Ticket Granting Ticket),或更簡單地說是 TGT,與之關聯的主體是 krbtgt/REALM@REALM。如果用戶實際上就是他們所說的真實身份(我們將在後面看到他們的演示方式),則可以使用 TGT 獲得其他服務票證而無需重新輸入密碼。

3.5.3 票據授權服務 - TGS(Ticket Granting Server)

票證授予服務器是 KDC 組件,它通過有效的 TGT 將服務票證分發給客戶端,從而保證了身份的真實性,以便在應用程序服務器上獲得請求的資源。TGS 可以看作是一個應用程序服務器(假設要訪問它,必須提供 TGT),該服務器提供服務票證的發行服務,重要的是不要混淆縮寫 TGT 和 TGS:第一個表示票證,第二個表示票務。

3.6 會話密鑰(Session Key)

如我們所見用戶和服務與 KDC 共享一個祕密。對於用戶此祕密是從其密碼派生的密鑰,而對於服務這是其密鑰(由管理員設置)。這些密鑰被稱爲長期密鑰,因爲它們在工作會話更改時不會更改。

但是,至少在客戶端在服務器上打開工作會話的時間內,用戶還必須與服務共享一個祕密:發行票證時由 KDC 生成的此密鑰稱爲會話密鑰。用於服務的副本由 KDC 封裝在票證中(無論如何,其應用服務器知道長期密鑰並可以對其進行解碼並提取會話密鑰),而用於用戶的副本則與用戶的長期密鑰封裝在加密的數據包中。會話密鑰在證明用戶的真實性方面起着基本作用,我們將在以下段落中看到。

3.7 身份驗證(Authenticator)

即使用戶 principal 存在於票證中並且只有應用程序服務器才能提取且可能管理此類信息(因爲票證已使用服務的密鑰進行了加密),但這不足以保證客戶端的真實性。當合法客戶將票證發送到應用程序服務器時,冒名頂替者可以捕獲(記住一個假設在開放且不安全的網絡下)票證,並在適當時機將其發送給非法獲取服務。另一方面,將機器的 IP 地址包括在可以使用的地方不是很有用:衆所周知,在開放和不安全的網絡中,地址很容易被僞造。爲了解決該問題,必須利用這樣一個事實,即客戶端和服務器至少在會話期間,具有一個只有他們才知道的會話密鑰(KDC 自生成它以來也知道它,但是從定義上來說它是受信任的!!!)。因此將應用以下策略:客戶端與包含票證的請求一起添加另一個包(身份驗證器),其中包含用戶 principal 和時間戳(在那時),並使用會話密鑰對其進行加密;必須提供服務的服務器在收到此請求後,將第一張 ticket 解包提取會話密鑰,如果用戶確實是他/她所說的話,則服務器可以對驗證者進行解密以提取時間戳。如果後者與服務器時間相差少於2分鐘(但是可以配置容差)則認證成功。這強調了屬於同一 realm 的機器之間同步的重要性。

3.8 重播緩存(Replay Cache)

冒名頂替者有可能同時竊取票證和驗證者並在驗證者有效的2分鐘內使用它們,這是非常困難但並非不可能的。爲使 Kerberos 5 解決這個問題,引入了重播緩存。在應用程序服務器中(但在 TGS 中),也可以記住最近2分鐘內到達的身份驗證器,如果它們是副本則可以拒絕它們。這樣只要冒名頂替者不夠聰明,無法複製票證和驗證器並使它們在合法請求到達之前到達應用程序服務器,就可以解決問題。 這確實是一個騙局,因爲當冒名頂替者可以訪問該服務時真實用戶將被拒絕。

3.9 憑據緩存(Credential Cache)

客戶端永遠不會保留用戶的密碼,也不會記住通過應用 string2key 獲得的密鑰:它們用於解密來自 KDC 的答覆並被立即丟棄。 但是另一方面,要實現單點登錄(SSO)特性,即要求用戶每個工作會話僅輸入一次密碼,則必須記住票證和相關的會話密鑰,該數據的存儲位置稱爲憑據緩存,該高速緩存需要放置的位置並不取決於協議,而是因實現方式而異。通常出於可移植性目的,它們位於文件系統(MIT 和 Heimdal)中。在其他實施方式(AFS 和 Active Directory)中,爲了在出現易受攻擊的客戶端的情況下提高安全性,將憑據緩存放置在僅內核可訪問且不能在磁盤上交換的內存區域中。

4 Kerberos 操作

最後獲得了前面段落中描述的概念之後,可以討論 Kerberos 的工作方式。我們將通過列出並描述身份驗證期間在客戶端和 KDC 之間以及客戶端和應用程序服務器之間傳遞的每個數據包來完成此操作。在這一點上,重要的是要強調應用程序服務器永遠不要直接與密鑰分發中心進行通信:票據服務即使由 TGS 打包,也只能通過希望訪問它們的客戶端才能到達服務。下面將列出我們將討論的消息(另請參見下圖):

  • AS_REQ 是初始用戶身份驗證請求(即使用 kinit 發出的請求)。此消息定向到稱爲身份驗證服務器(AS)的 KDC 組件;
  • AS_REP 是身份驗證服務器對先前請求的答覆。基本上它包含 TGT(使用 TGS 密鑰加密)和會話密鑰(使用發出請求的用戶的密鑰加密);
  • TGS_REQ 是從客戶端到票據授權服務器(TGS)的服務票證請求。該數據包包括從先前的消息中獲得的 TGT 和由客戶端生成並使用會話密鑰加密的身份驗證器。
  • TGS_REP 是票據授權服務器對先前請求的答覆。位於其中的是請求的服務票證(使用服務的密鑰加密)和由 TGS 生成並使用 AS 生成的先前會話密鑰加密的服務會話密鑰;
  • AP_REQ 是客戶端發送到應用程序服務器以訪問服務的請求。這些組件是從 TGS 獲得的帶有先前答覆的服務票證,以及由客戶端再次生成的身份驗證器,但是這次使用服務會話密鑰(由TGS生成)進行了加密;
  • AP_REP 是應用程序服務器提供給客戶端的答覆,以證明它確實是客戶端期望的服務器。並非總是請求此數據包,客戶端僅在需要相互認證時才向服務器請求。
    Kerberos 請求過程圖

現在參考 Kerberos 5 更詳細地描述每個先前的階段,但會指出與版本4的區別。但是應該記住 Kerberos 協議相當複雜,本文檔不作爲指南。 對於那些想知道確切的操作細節的人(無論如何,這些細節已經在 RFC1510 中編寫了)。下面的討論被有意抽象的,但對於那些檢查 KDC 日誌的人員來說理解各種身份驗證轉換和發生的任何問題就足夠了。

注意:後續段落將未加密的數據括在圓括號()中,將加密的數據括在大括號{}中:( x, y, z )表示x,y,z未加密;{ x, y, z }K 表示使用對稱密鑰 K 一起加密了x,y,z。同樣重要的是要注意,包中列出的組件的順序與實際消息(UDP 或 TCP)中的實際順序無關。討論非常抽象,如果您希望獲得更多詳細信息,請參閱具有描述性協議 ASN.1 的背景知識的 RFC1510。

4.1 身份驗證服務請求 - AS_REQ(Authentication Server Request)

在此階段中稱爲初始身份驗證請求,客戶端(kinit)向 KDC(更具體地爲 AS)請求票證授予票證。該請求是完全未加密的,如下所示:

AS_REQ = (PrincipalClient , PrincipalService , IP_list , Lifetime )

其中:

  • PrincipalClient 是與尋求身份驗證的用戶關聯的 principal(例如[email protected]);
  • PrincipalService 是與票證要求的服務關聯的 principal,因此是字符串krbtgt/REALM@REALM(請參閱 Note *);
  • IP_list 是一個 IP 地址列表,指示可以在其中使用將要發出的票證的主機(請參閱 Note **);
  • Lifetime 是要發行的票證的最大有效時間(要求的)。

Note *:將 PrincipalService 添加到初始身份驗證請求似乎是多餘的,因爲這將一直設置爲 TGS 主體,即krbtgt/REALM@REALM。但是事實並非如此,實際上計劃在工作會話中僅使用一項服務的用戶不會使用單一登錄,而是可以直接向 AS 請求該服務的票證從而跳過隨後的請求到TGS。從操作角度來看(MIT 1.3.6),以下命令已足夠:kinit -S imap/[email protected] [email protected]

Note **:IP_list 也可以爲空,在這種情況下任何機器都可以使用相應的票證。這解決了那些在 NAT 下的客戶端的問題,因爲它們的請求將以與請求用戶的源地址不同但與進行 NAT 的路由器相同的源地址到達服務。相反對於具有多個網卡的計算機,IP_list 應該包含所有網卡的 IP 地址:實際上很難預先預測提供服務的服務器將與哪個連接聯繫。

4.2 身份驗證服務回覆 - AS_REP(Authentication Server Reply)

當前一個請求到達時,AS 會檢查 KDC 數據庫中是否存在 PrincipalClient 和 PrincipalService:如果兩者中至少有一個不存在則會向客戶端發送錯誤消息,否則 Authentication Server如下處理答覆:

  • 它隨機創建一個會話密鑰,該密鑰將是客戶端和 TGS 之間共享的祕密。假設爲 SKTGS
  • 它將創建 TGT 並將其放入請求用戶的 principal,principal 服務(通常爲 krbtgt/REALM@REALM,,但請閱讀上一段的 Note *),IP地址列表(前三部分信息是在它們通過 AS_REQ 數據包到達時進行復制),
    時間戳格式的日期和時間(KDC 的日期和時間),lifetime(請參閱 Note *)以及最後的會話密鑰。 SKTGS; 因此 TGT 如下所示:

TGT = (PrincipalClient , krbtgt/REALM@REALM , IP_list , Timestamp , Lifetime , SKTGS )

  • 它生成併發送包含以下內容的答覆:先前創建的票證,已使用服務的密鑰進行了加密(我們將其稱爲KTGS); 服務 principal、timestamp、lifetime 和 會話密鑰均使用請求服務的用戶的密鑰進行了加密(我們將其稱爲KUser),總結爲:

AS_REP = {PrincipalService , Timestamp , Lifetime , SKTGS}KUser { TGT }KTGS

該消息似乎包含冗餘信息(PrincipalService、Timestamp、Lifetime 和會話密鑰)。但是事實並非如此:由於 TGT 中存在的信息是使用服務器的密鑰加密的,客戶端無法讀取它,因此需要重複該信息。 此時當客戶端收到回覆消息時,它將要求用戶輸入密碼,鹽與密碼連接在一起,然後應用 string2key 函數:使用生成的密鑰,嘗試使用存儲在數據庫中的用戶的密鑰來解密由 KDC 加密的消息部分。 如果用戶確實是他/她說的人,並因此輸入了正確的密碼,則解密操作將成功,因此可以提取會話密鑰,並將 TGT(保持加密狀態)存儲在用戶的憑據緩存中。

Note *:實際 lifetime,即票證中的實際 lifetime 是以下值中的最小值:客戶端請求的 lifetime、用戶 principal 中包含的 lifetime 以及服務 principal 中包含的 lifetime。實際上,在實現方面,可以從 KDC 的配置中設置另一個限制,並將其應用於任何票證。

4.3 票據授權服務請求 - TGS_REQ(Ticket Granting Server Request)

此時,用戶已經證明是他/她所說的那個人(因此,在他/她的憑證緩存中有一個 TGT 和會話密鑰 SKTGS,想要訪問該服務但還沒有合適的 ticket,則發送一個 TGS_REQ,其構造如下:

  • 使用用戶 principal、客戶端機器時間戳創建身份驗證器,並使用與 TGS 共享的會話密鑰對所有內容進行加密,即:

Authenticator = { PrincipalClient , Timestamp} SKTGS

  • 創建一個請求數據包,其中包含:需要票證且未加密生命週期的服務 principal;該票證已使用TGS的密鑰加密的 TGT;和剛剛創建的身份驗證器。概括起來如下:

TGS_REQ = ( PrincipalService , Lifetime, Authenticator) { TGT }KTGS )

4.4 票據授權服務重放 - TGS_REP(Ticket Granting Server Replay)

當先前的請求到達時 TGS 首先驗證 KDC 數據庫中是否存在所請求的服務的主體(PrincipalService):如果存在,則使用 krbtgt/REAM@REALM 的字符串打開 TGT 並提取會話密鑰SKTGS 作爲要解密的身份驗證器。對於要發行的票據服務,進行檢查以下情況是否有肯定的結果:

  • TGT 尚未過期;
  • 身份驗證器中存在的 PrincipalClient 與 TGT 中存在的 PrincipalClient 相匹配;
  • 驗證者不存在於重播緩存中並且尚未過期;
  • 如果IP_list不爲null,它將檢查請求數據包(TGS_REQ)的源 IP 地址是否爲列表中包含的 IP 地址之一;

先前檢查的條件證明 TGT 確實屬於發出請求的用戶,因此 TGS 開始按以下方式處理答覆:

  • 它隨機創建一個會話密鑰,該密鑰將是客戶端和服務之間共享的祕密。假設爲 SKService
  • 它創建服務票證,將請求用戶的 principal、服務的 principal、IP地址列表、時間戳格式的(KDC的)日期和時間、生存期(作爲TGT生存期與與服務 principal 相關聯),最後是會話密鑰 SKService。被稱爲 TService 的新票證是:

TService = ( PrincipalClient , PrincipalService , IP_list , Timestamp , Lifetime , SKService)

  • 它發送包含以下內容爲回覆消息:先前創建的票證、已使用服務密鑰加密(我們將其稱爲 KService )、服務 principal、時間戳、生存期 和 新會話密鑰都使用從 TGT 提取的會話密鑰進行了加密。 概括起來如下:

TGS_REP = {PrincipalService , Timestamp , Lifetime , SKService}SKTGS { TService }KService

當客戶端收到答覆後,在憑據緩存中具有會話密鑰 SKTGS,它可以解密包含其他會話密鑰的消息部分,並將其與服務票證 TService 一起存儲,但是該票證仍保持加密狀態。

4.5 應用服務請求 - AP_REQ(Application Server Request)

具有訪問服務的憑據(即票證和相關會話密鑰)的客戶端可以通過 AP_REQ 消息嚮應用程序服務器請求對資源的訪問。應該牢記的是與先前涉及 KDC 的消息不同,AP_REQ 不是標準的而是根據應用程序而有所不同,因此應用程序程序員負責建立策略,客戶端將使用該策略使用其憑據向服務器證明其身份。 但是,我們可以通過示例考慮以下策略:

  • 客戶端創建一個包含用戶 principal 和 時間戳的身份驗證器,並使用與應用程序服務器共享的會話密鑰 SKService 加密所有內容,即:

Authenticator = { PrincipalClient , Timestamp }SKService

  • 它創建一個包含服務票證 TService 的請求數據包,該服務票證已使用其密鑰和剛剛創建的身份驗證器進行了加密,概括起來如下:

AP_REQ = Authenticator { TService }KService

當先前的請求到達時,應用程序服務器使用所請求服務的密鑰打開票證,並提取會話密鑰 SKService,它將其用於解密身份驗證器。爲了確定發出請求的用戶是真實的,並因此授予對該服務的訪問權限,服務器將驗證以下條件:

  • 票據尚未過期;
  • 身份驗證器中存在的 PrincipalClient 與票證中存在的 PrincipalClient 相匹配;
  • 驗證者不存在於重播緩存中並且尚未過期;
  • 如果 IP_list(從票證中提取)不爲空,則檢查請求包的源 IP 地址(AP_REQ)是否爲列表中包含的IP地址之一;

注意:先前的策略與票證授權服務器用來檢查請求服務票證的用戶的真實性的策略非常相似,但這不足爲奇,因爲我們已經解釋了 TGS 可以被視爲應用服務器,其服務是向那些使用 TGT 證明自己身份的人提供票證。

4.6 應用服務重放 - AP_REP (缺失)


4.7 身份預認證

從 Authentication Server Reply(AS_REP)的說明中可以看出,在分發票證之前 KDC 只需檢查數據庫中是否存在請求用戶和服務提供者的 principal。然後尤其是在涉及到 TGT 的請求時這甚至會更加容易,因爲 krbtgt/REALM@REALM 確實存在,因此只要知道用戶的 principal 就可以通過簡單的初始身份驗證請求獲得 TGT 就足夠了。顯然,如果請求來自一個非法用戶,則無法使用該 TGT,因爲他們不知道密碼,也無法獲取用於創建有效身份驗證器的會話密鑰。但是以這種簡單方式獲得的該票證可能會遭受暴力攻擊,以試圖猜測該票證旨在提供的服務的長期密鑰。顯然,即使使用當前的處理能力,猜測服務的祕密也不是一件容易的事,然而 對於 Kerberos 5 還是引入了預認證概念以增強安全性。因此,如果 KDC 策略(可配置)請求對初始客戶端請求進行身份預驗證,則身份驗證服務器將以錯誤包答覆,指示需要進行身份預驗證。鑑於錯誤,客戶端要求用戶輸入密碼並重新提交請求,但是這次添加了用用戶長期密鑰加密的時間戳,我們知道這是通過在加鹽後將 string2key 應用於未加密的密碼(如果有)來獲得的。這次,由於KDC知道用戶的祕密密鑰,因此它嘗試解密的請求中存在時間戳,如果成功,並且時間戳符合要求,即包含在已建立的容限內,則它判斷請求的用戶是真實的,並且身份驗證過程可以正常繼續。

重要的是要注意,身份預驗證是 KDC 策略,因此協議不一定要求它。在實現方面默認情況下 MIT Kerberos 5 和 Heimdal 禁用了預身份驗證,而 Windows Active Directory 和 AFS kaserver(這是經過預身份驗證的 Kerberos 4)中的 Kerberos 會請求它。

5 深入理解票據(Tickets in-depth)

如前面所述,既然已經討論了 KDC 的操作以及身份驗證所涉及的主機之間的消息,那麼現在我們來看看票據。這些取決於它們是否在其中設置了屬性(也稱爲標誌),它們以某種方式運行。我在下面列出了最重要的票據類型,即使考慮到我在談論協議也不完全正確,我仍將引用 MIT Kerberos 5 的 1.3.6 版(足以使事情變得清楚)。

5.1 初始化票據(Initial tickets)

初始化票據是直接從 AS 獲得的,即當用戶必須通過輸入密碼進行身份驗證時,從這裏可以推斷出,TGT 始終是初始票據。另一方面,服務票據由 TGS 在提供 TGT 時分發,因此不是初始票據。但是該規則有一個例外:爲了保證用戶僅在幾秒鐘之前輸入密碼,某些 Kerberos 應用程序可能會要求服務票據是初始的。在這種情況下,儘管不是 TGT,但票證是從 AS 而不是 TGS 請求的,因此是初始票據。在操作方面,用戶 pippo 希望獲得機器 mbox.example.com 上 imap服務 的初始票證(因此無需使用 TGT),因此使用以下命令:

[pippo@client01 pippo]$ kinit -S imap/[email protected] [email protected]
Password for [email protected]: 
[pippo@client01 pippo]$ 
[pippo@client01 pippo]$ klist -f
Ticket cache: FILE:/tmp/krb5cc_500
Default principal: [email protected]

Valid starting     Expires            Service principal
01/27/05 14:28:59  01/28/05 14:28:39  imap/[email protected]
        Flags: I

Kerberos 4 ticket cache: /tmp/tkt500
klist: You have no tickets cached

應該注意標誌 I 的存在,表明它是一張初始票。

5.2 可續票據(Renewable tickets)

可以將可續票據重新提交給 KDC 進行更新,即在整個生命週期內將其重新分配。顯然僅當票據尚未過期且未超過最大續訂時間(在密鑰分發中心數據庫中設置)時,KDC 纔會接受續訂請求。能夠更新票據的原因在於出於安全原因需要具有短時票據,而不必長時間重新輸入密碼:例如假設一項工作必須處理數天且無需任何人工干預 。在以下示例中,pippo 要求購買一張門票,該門票最多可使用一小時,但可續簽8天:

kinit -l 1h -r 8d pippo
Password for [email protected]:
[pippo@client01 pippo]$ 
[pippo@client01 pippo]$ klist -f
Ticket cache: FILE:/tmp/krb5cc_500
Default principal: [email protected]

Valid starting     Expires            Service principal
01/27/05 15:35:14  01/27/05 16:34:54  krbtgt/[email protected]
        renew until 02/03/05 15:35:14, Flags: RI


Kerberos 4 ticket cache: /tmp/tkt500
klist: You have no tickets cached
while for pippo to renew his ticket without re-entering the password:

[pippo@client01 pippo]$ kinit -R
[pippo@client01 pippo]$ 
[pippo@client01 pippo]$ klist -f
Ticket cache: FILE:/tmp/krb5cc_500
Default principal: [email protected]

Valid starting     Expires            Service principal
01/27/05 15:47:52  01/27/05 16:47:32  krbtgt/[email protected]
        renew until 02/03/05 15:35:14, Flags: RIT


Kerberos 4 ticket cache: /tmp/tkt500
klist: You have no tickets cached

5.3 可轉發票據(Forwardable tickets)

假設我們在具有相關 TGT 的機器上進行工作會話,並希望從該機器登錄另一臺機器並保留 ticket,可轉讓票據是解決此問題的方法。從一臺主機轉發到另一臺主機的票據本身是可轉發的,因此,一旦通過身份驗證,便可以在所有所需計算機上訪問登錄名,而不必重新輸入任何密碼。

爲了在沒有 Kerberos 的情況下獲得相同的結果,有必要使用安全性低得多的方法,例如 rsh 或 ssh 的公鑰身份驗證。但是,後一種方法在用戶主目錄位於網絡文件系統(例如 NFS 或 AFS)上的系統可能不可行,因爲私鑰(應爲私有)將通過網絡。

6 交叉認證(Cross Authentication)

我們已經提到了屬於某個 realm 的用戶驗證和訪問另一個 realm 的服務的可能性。稱爲交叉身份驗證的此特徵基於以下假設:所涉及的 realm 之間存在信任關係,這可能是單向的,這意味着 realm A 的用戶可以訪問 realm B 的服務,但反之則不能;或者是雙向的,正如人們可能期望的那樣,也可以相反。在以下各文章段落中,我們將研究交叉身份驗證,將信任關係分爲 直接、傳遞和分層。

6.1 直接信任關係(Direct trust relationships)

這種類型的信任關係是基本的,是交叉身份驗證的基礎並且用於構造其他兩種類型的關係,我們將在後面介紹。當 realm B 的 KDC 直接信任 realm A 的 KDC 時,就會發生這種情況,從而允許後者的用戶訪問其資源。從實際的角度來看,直接信任關係是通過使兩個參與的 KDC 共享一個密鑰來獲得的(如果需要雙向信任,則密鑰將變爲兩個)。爲此,引入了遠程 TGT 的概念,在兩個 realm A 和 B 的示例中,TGT 的形式爲 krbtgt/B@A,並使用相同的密鑰添加到兩個 KDC 中,該密鑰是確保兩個 realm 之間信任的祕密。顯然,要使其成爲雙向的(即 A 也信任 B),有必要在兩個 KDC 中創建遠程 TGT krbtgt/A@B,並將它們與另一個密鑰相關聯。

我們將在下面的示例中很快看到,引入遠程 TGT 使得交叉身份驗證成爲常規 intra-realm 身份驗證的自然概括:這說明只要接受一個 realm 的 TGS 可以驗證另一 realm 的 TGS 發出的遠程 TGT,則先前對 Kerberos 操作的描述將繼續有效。請注意,當遠程 TGT 不是由 AS 發佈時(由本地發佈,而是由本地票據授權服務器在發佈本地 TGT 時發生)時,會出現形式上的異常。

現在讓我們看一個例子來闡明所有這些,假設示例 EXAMPLE.COM 的用戶 pippo(其關聯 principal 爲 [email protected])希望通過 ssh 訪問屬於 TEST.COM realm 的 pluto.test.com 服務器:

  • 如果 Pippo 在 EXAMPLE.COM realm 中尚未具有 TGT,他將發出初始身份驗證請求(kinit)。顯然答覆來自其 realm 的 AS。
  • 他給出了 ssh [email protected] 命令,該命令應在 pluto.test.com 上打開遠程 shell 而無需重新輸入密碼。
  • ssh 客戶端對 DNS 進行兩次查詢:計算出 pluto.test.com 的 IP,然後對剛獲得的地址進行反向查詢,以獲取規範形式的主機名(FQDN)(在這種情況下它與 pluto.test.com 一致);
  • 然後,由於先前的結果 ssh 客戶端意識到目的地不屬於用戶的 realm,因此向該 realm 的 TGS 詢問 EXAMPLE.COM(請注意,它爲此向其 realm 的 TGS 詢問)以獲得遠程TGT krbtgt/[email protected];
  • 通過遠程 TGT,它向 TEST.COM realm 的 TGS 索要 host/[email protected] 服務票據;
  • TEST.COM 票據授權服務收到請求時,它將檢查其數據庫中是否存在 principal krbtgt/[email protected],它可以用來驗證信任關係。
    如果此驗證是肯定的,則最終會發出服務票據(使用 host/[email protected] 的密鑰加密),然後 pippo 將其發送到主機 pluto.test.com 以獲取遠程 shell。

6.2 傳遞信任關係(Transitive trust relationships)

當必須進行交叉身份驗證的 realms 的數量增加時,要交換的密鑰的數量將平方增加。 例如如果有5個 realms 並且關係必須是雙向的,則管理員必鬚生成20個密鑰(將5個元素的組合乘以2乘以2)。

爲解決此問題,Kerberos 5 在信任關係中引入了可傳遞性:如果 realm A 信任 realm B,realm B 信任 realm C,則 A 將自動信任 C。此關係屬性將大大減少密鑰的數量(即使身份驗證次數增加)。

但是,仍然存在一個問題:如果身份驗證路徑(capath)不是直接的則客戶端無法猜測。 因此,必須通過在每個客戶端的配置中創建一個特殊的節([capaths])來告知他們正確的路徑。 這些路徑也必須是 KDC 已知的,KDC 將使用它們來檢查運轉。

6.3 分層信任關係(Hierarchical trust relationships)

如果在組織內部使用以大寫字母表示 DNS 域名稱的 realm 的約定(強烈建議選擇),並且如果後者屬於一個層次結構,則 Kerberos 5 將支持(具有層次結構的)具有信任關係的相鄰 realm(自然而然,假定的信任必須由適當的密鑰來支持),並且將自動構造(無需附加功能)可傳遞認證路徑。 但是,管理員可以通過強制客戶端配置中的限制來更改此自動機制(例如,出於效率方面的考慮)。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章