認證系統設計經典會話

Bill Bryant,首次寫與1988年2月
Theodore Ts'o與1997年2月整理並轉換成HTML,而且追加了 afterword 章節來描述V5版本的一些變化算法

前言

本文虛構了一個關於公網認證系統--Charon構建過程的對話,隨着對話的進行,Athena和Euripides探討了公共網絡環境裏廣泛存在安全問題,並在Charon系統設計之初就考慮好了這些問題的解決方式。因此直到對話完成,Athena和Euripides纔算真正的把系統設計好。數據庫

當系統設計好後,Athena把系統的名字從Charon改爲了Kerberos。很是巧合的是,在MIT的一個項目--Athena中,設計和實現的認證系統名稱就叫作Kerberos。緩存

對話中的「Kerberos」與1988年發表的「Kerberos:一個公共網絡的認證系統「有着驚人的類似之處。安全

Scene I

在一個小隔間裏,Athena和Euripides正在兩個相鄰的終端上工做服務器

Athena:Rip,大家這個分時共享系統就是個累贅。由於其餘人都登錄着,它慢的使我根本無法成個人工做。網絡

Euripides:這個不要向我抱怨,我只是個打工的。session

Athena:難道你不知道咱們的需求嗎?咱們真正想要的是給每一個人一個本身的工做站,以後再用網絡連接全部的工做站,從而使你們能相互通訊,這樣他們就不用擔憂共享計算週期的問題。ide

Euripides:那麼咱們須要多少工做站呢,1000個?測試

Athena:差很少加密

Euripides:哪你有沒有調研過普通工做站的磁盤,通常來說是沒有足夠的空間來安裝你在共享機器上全部的軟件的?

Athena:這個我已經想好了,咱們能夠把所需的軟件裝在不一樣的服務器上,當你登錄到本身的工做站後,你能夠經過網絡向這些服務器發請求來使用那些軟件服務。這樣還能使全部的工做站都使用相同的軟件版本,軟件升級也會很便捷,只用把服務器上的軟件升級就能夠了,不用到每一個工做站上面去操做。

Euripides:好吧,可是你怎麼管理我的文件呢?在分時共享系統中,我能夠經過任意一個和系統鏈接的終端登錄並訪問我本身的文件。你這樣設計後,我是否能經過任意工做站來獲取個人我的文件,仍是說我要隨身帶個軟盤來保存我本身的文件呢?

Athena:我想咱們能夠用另一臺服務器來存儲私有文件,這樣你就能夠登錄任意的工做站來獲取你本身的文件。

Euripides:那打印功能怎麼辦,難道讓每一個工做站都要有本身的打印機嗎?你用誰的錢來買這些設備呢?還有電子郵件怎麼處理,怎麼把郵件分發到全部的工做站上呢?

Athena:嗯…,很明顯,咱們沒有錢給每一個工做站配置一臺打印機,可是咱們能夠用一臺機器專門用來作打印服務。你把你的打印任務發給打印服務機,由它來幫你打印。你也能夠用一樣的思路來處理電子郵件,由一臺機器專門作郵件服務,若是你想要你的郵件,你鏈接這個服務,由他來把你的郵件挑揀出來。

Euripides:你的工做站系統聽起來是很好。當我有了本身的工做站,你知道我會作什麼嗎,我會找出你的名字,並使個人工做站認爲我是你,這樣我就能夠鏈接到郵件服務獲取你的郵件,我還能夠連上文件服務器來刪除你的文件,我還能夠…

Athena:你真的會這樣作嗎?

Euripides:是的,那些服務怎麼能知道如今是我在操做而不是你呢?

Athena:呃,我不知道,我須要好好想一想這個問題。

Euripides:聽起來是的。若是你知道怎麼作了請必定告訴我。

Scene II

次日早上,在Euripides 的辦公室,Euripides正在他的辦公桌前讀他的點子郵件,Athena敲門進來

Athena:哈哈,我已經找到一種方式來加密網絡環境,從而阻止像你這樣調皮的傢伙不能假裝成別人來使用那些服務。

Euripides:真的嗎,坐下來說吧。

Athena:在我開始以前,我能不能給咱們的討論定下一個基本準則?

Euripides:什麼準則?

Athena:假如我說了下面的話:「我想看個人電子郵件,因此我鏈接上郵件服務,告訴郵件服務把郵件發到個人工做站。」實際上,並非我直接鏈接郵件服務,而是我使用了一個程序去鏈接郵件服務,一個稱做郵件服務客戶端的程序。
可是當我每次描述用戶和服務交互時,我不會說「客戶端作了什麼「,而是會說「我作了什麼」,因此請記住是客戶端做爲個人代理作了這些事。我這樣講有沒有問題?

Euripides:沒有問題。

Athena:針對網絡安全問題,最笨的方式是每次郵件服務都讓用戶提供密碼來證實用戶身份。

Euripides:這的確是夠笨的。在這樣一個系統中,須要每個服務都知道你的密碼。若是網絡裏面有一千個用戶,每一個服務都要有一千個用戶的密碼;當你想要修改密碼時,你還得聯繫全部的服務去一個個修改。我想你的系統不會這麼笨吧。

Athena:個人系統不笨。他像這樣工做:不只僅是用戶有密碼,服務也有密碼。每一個用戶知道本身的密碼,每一個服務也知道本身的密碼,而且還有一個認證服務知到全部的密碼,包括用戶的和服務的。認證服務把這些密碼存儲在一箇中央倉庫中。

Euripides:你有給這個認證服務起好名字嗎?

Athena:我尚未想好,你有什麼想法嗎?

Euripides:那個幫助死者過冥河的擺渡人名字怎麼樣?

Athena:Charon嗎?

Euripides:是的,就是他,除非你證實你的真實身份,不然他是不會擺渡你的。

Athena:Rip,你又來這一套,從新杜撰羅馬神話。Charon並不關係你的身份,他只確保你已經死掉就夠了。

Euripides:哪你有沒有一個更好的名字?

Athena:沒,尚未。

Euripides:那就把這個認證服務叫「Charon 」吧。

Athena:好吧,那我就開始描述這個系統了。

咱們假定你如今要用郵件服務。在這個系統裏,你不能直接使用一個服務,除非Charon告訴那個服務你就是你所聲明的那我的。而且除非你先向Charon認證,不然你也不能獲取到那個服務。當你向Charon認證時,你同時得告訴Charon你想使用哪個服務,就是說若是你想用郵件服務,你得明確告訴Charon。

接着,Charon要求你提供認證信息。你向Charon提供你的密碼,而後Charon和註冊在中央數據庫中的密碼進行對比,若是密碼時匹配的,Charon認爲你證明了你的身份。

接下來,Charon要告訴郵件服務你就是你所聲明的那我的。由於Charon知道全部服務的密碼,固然也包括郵件服務的。很明顯Charon能夠告訴你郵件服務的密碼,當你向郵件服務發起請求時你能夠用這個密碼證實你已經向Charon認證過了。

如今的問題是,Charon不能直接給你密碼,由於你知道這個密碼後,下一次你想訪問郵件服務,你就能夠繞過Charon不用再認證了,以後你仍能夠假裝別人,用別人的名字來訪問郵件服務獲取他的郵件了。

因此,Charon會給你一個郵件服務的票據(TICKET)而不是直接給你密碼。這個票據裏面包含了你的名字,而且會利用郵件服務的密碼進行加密。

TICKET = {username} K_server

  • {X}K_Y 表示 用K_Y對X進行加密。

拿到票據後,你如今能夠向郵件服務請求你的郵件了,你告訴郵件服務你的名字,同時把票據發給郵件服務來證實你的身份。

郵件服務拿到票據後,首先用本身的密碼進行解碼,若是能正常解碼,郵件服務就能拿到Charon存放在票據中的名字。

郵件服務再用票據中的名字和你提供的名字進行對比,若是名字一致,郵件服務就認爲你是你所聲明的人,就把你的郵件給你。

你以爲這個方法怎樣?

Euripides:我有幾個問題。

Athena:預料之中,你繼續講。

Euripides:當一個服務解碼一個票據,他如何判斷本身正確解碼了(這個票據是針對本身這個服務的,而不是用戶申請訪問別的服務對應的票據)?

Athena:這個我還沒考慮好。

Euripides:最好能把服務的名字也放到票據中。這樣當一個服務解碼票據後,他能夠經過能不能在票據中正確找到本身的名字來判斷解碼是否成功。

Athena:聽起來不錯,那麼如今票據就變成了這樣

TICKET - {username: servicename} K_server

Euripides:這樣票據就包含用戶名和服務名。

Athena:再用服務的密碼進行加密。

Euripides:但是我仍是不認爲這些信息就能保證票據的安全性。

Athena:舉個例子呢。

Euripides:好比說,你向Charon要了一個郵件服務的票據。Charon準備好了票據,並把你的名字「tina」放了進去。假定在Charon經過網絡把票據發給你的過程當中我把這個票據複製了一份,而後我欺騙個人工做站說我就是tina,這樣工做在我工做站的郵件客戶端程序就會認爲我就是你。利用你的名字,郵件客戶端再利用偷來的票據向郵件服務發請求。這樣郵件服務收到請求後解碼了票據,並會驗證經過,郵件服務就會把你的服務發給我。

Athena:嗯,是的,這個設計仍是不完美。

Euripides:可是我知道一種方式來修復這個問題,或者說局部解決這個問題。我認爲Charon須要在票據中包含更多的信息。除了用戶名,Charon還須要把用戶請求票據時的網絡地址包含進去,這樣就能夠多一個安全保證。

我用下面的過程來證實:假如說我如今偷取了你的票據,這個票據裏面有你工做站的地址,這個地址和我工做站的地址是不同的。當我僞造你的名字和偷來的票據請求郵件服務時,郵件服務從票據中解碼出名字和地址並和請求中的用戶名和地址進行匹配,雖然用戶名匹配成功了,可是地址不匹配,很明顯這個票據被偷了,服務器就拒絕此次請求。

Athena:太好了,我但願我也能想到這樣的方法。

Euripides:哈,這就是個人目的。

Athena:那麼修改後的票據就變成了

TICKET = {username:ws_address:servicename} K_server

Athena:我如今好興奮,讓我構建一個Charon系統來看看他是否能工做吧。

Euripides:還不能這麼快,我對這個系統還有幾個疑問。

Athena:好吧,繼續。

Euripides:目前來看,每次只要我想訪問一次服務,我都得獲取一個票據。若是我一成天都在工做,我確定會屢次要獲取個人郵件信息。若是每次訪問服務都得獲取一個票據,那我是不會喜歡這個系統的。
Athena:呃…,爲何票據不能重複使用呢,當你獲取一個票據後,你是能夠重複使用的。比方說,當郵件客戶端程序向服務請求時,他把票據複製一份,把這個副本發送到服務端。

Euripides:聽起來不錯,可是仍是有問題。目前來看,當我要訪問一個我尚未票據的服務時,我都得向Charon提供個人密碼。例如我想訪問個人文件,我得向Charon提供個人密碼來獲取一個票據,當我想向郵件服務獲取個人郵件時我還得向Charon提供個人密碼,假如我又想打印些什麼東西,我又得訪問Charon,你能想象到那個畫面的。

Athena:呃,是的。

Euripides:這還不是最糟的,目前你向Charon認證時,你以明文的形式在網絡上傳播你的密碼。那些像你這樣聰明的人確定能夠經過模擬網絡來偷取別人的密碼,若是我有了你的密碼,我又能夠以你的名義使用任意服務。

Athena:這些都是嚴重的問題,我須要從新設計一下。

Scene III

隔天早上,Athena在咖啡間碰見了Euripides,並在他的接滿水後,把手搭在了他的肩膀上,一塊兒向咖啡機走去

Athena:我想了一個新版本的Charon能夠解決咱們的問題。

Euripides:真的嗎,這麼快?

Athena:嗯,這個問題讓我想了一夜。

Euripides:這必定是你的負罪感,讓咱們找個小隔間再討論討論吧?

Athena:爲何不呢?

兩人走向一個小隔間

Athena:做爲開始部分,我會從新陳述一下咱們的問題,看看咱們的系統是否是真的須要這些功能。

Athena:第一個需求:用戶只用在他們登錄進工做站的時候輸入他們的密碼一次。這個需求指的是你不用在每次獲取其餘服務的票據時都要輸入密碼。第二個需求:密碼不能以明文的形式在網絡上傳播。

Euripides:是的

Athena:對於第一個需求:你只須要輸入一次你的密碼,爲了知足這個需求,我會引入一個新的服務,一個叫作「票據分發」(ticket-granting)服務,當用戶向Charon認證完成後,這個服務就會向這個用戶分發票據。若是你有這個票據分發服務的票據(TGT),你就可使用這個票據分發服務。
票據分發服務能夠簡單看成是Charon的一個變體,他也能訪問中央數據庫。Charon中的這個票據分發服務可讓你用票據代替密碼來認證。

如今,認證系統將這樣工做:你登錄到你的工做站,而後利用Kinit這個程序來鏈接Charon服務,以後你向Charon提供憑據,Kinit從Charon服務獲取你對應的TGT。

假如如今你想要訪問郵件服務,而你尚未郵件服務的票據,你就能夠用TGT向Charon來獲取郵件服務的票據,而不是使用密碼來獲取這個票據。

Euripides:那我須要訪問其餘服務時要不要每次都得獲取一個新的TGT呢?

Athena:不用,記不記得上次咱們達成的共識,票據是能夠重複使用的。一旦你有一個TGT,你不須要再獲取一個,以後你就能夠重複使用這個TGT來獲取其餘服務的票據。

Euripides:嗯,頗有道理。由於你能夠重複使用票據,因此一旦票據分發服務給你一個針對特定服務的票據(ST),就不須要再獲取這票據了。

Athena:是的,這樣是否是比較簡潔。

Euripides:嗯,到目前爲止還行,只要在獲取TGT時不經過明文在網絡上傳輸個人密碼。

Athena:就像我說的,我這問題我也解決了。事實上,當向Charon請求TGT時,我表述的好像是我要經過網絡發送你的密碼,但這並非必須的。

真實狀況是,當用Kinit程序向Charon獲取TGT時,kinit並不向Charon服務發送密碼,kinit只發送你的名字。

Euripides:好

Athena:Charon服務利用你的名字來查找你的密碼,接着Charon構造一個包含TGT的數據包,在Charon把這個數據包發給你以前,他會用你的密碼對數據包進行加密。

你的工做站收到這個數據包後,提示你輸入密碼,kinit會嘗試用你輸入的密碼來解碼這個數據包,若是解碼成功,預示着你認證成功,而且你會擁有TGT,而後你能夠用這個票據來獲取你想要服務的票據。

這個是否是你所想要的?

Euripides:我還不清楚,我須要再考慮考慮。我認爲你剛纔描述的那部分系統功能工做的至關好,它只須要我認證一次,此後Charon會自動的爲我分發其餘服務的票據也不用我再關心。可是關於票據的設計我仍是有困惑,由於基於一個前提,那就是票據是可重複用的,我贊成票據能夠重複使用,可是可重複用本質上講是危險的。

Athena:具體來講呢

Euripides:打比方來講,假如你使用了一個不安全的工做站,期間你獲取了郵件服務的票據、打印服務的、文件服務的,而後你退出了工做站。

如今假定我也登錄到了這個工做站,而且找到了這些票據。我呢,又比較喜歡製造麻煩,因此我把個人名字改爲你的來欺騙工做站說我就是你,由於那些票據都是用你的名字生成的,因此我能夠用郵件客戶端來獲取你的郵件,也能獲取你的文件,也能用你的帳號發送成千上萬的打印任務,全部的這一切都是由於你把票據忘在了這個工做站上。

而且也沒有什麼方法能阻止我把這些票據再複製下來,這樣我就能夠一直使用它們了。

Athena:這個很好解決呀,咱們能夠寫一段程序在用戶登出時銷燬用戶的票據,這樣你就不能使用了。

Euripides:好吧,很明顯你的系統須要一個銷燬程序,可是讓用戶依賴於這樣一個程序是愚蠢的。你不能確保用戶在每一次使用完工做站登出時都執行這個銷燬程序,即使你依賴於用戶執行銷燬程序,在下面的場景下也有問題

我寫了一個程序,它能夠監聽網絡,當有服務票據從網絡上傳播時我就把它複製下來。假如我想陷害你,當你登錄進工做站時,我也把這個程序打開,從而能copy你的票據。

當你完成工做退出工做站並離開後,我把個人工做站地址篡改爲你的地址,更改用戶名使個人工做站相信我就是你,這樣我就有了你的票據,你的名字,你的地址,我又能夠以你的名義從新使用這些票據。

即使是你在登出時銷燬了你的票據也沒有關係,由於我偷的這些票據只要我想用就會一直有效,而這都是由於你如今的票據設計裏面並無對票據的使用次數或者使用時間作限制。

Athena:哦,我知道你所說的了,票據永久有效是一個大的安全隱患。咱們必須限制一個票據可用的最大時長,也許咱們能夠給每一個票據一些過時信息。

Euripides:實際上,我認爲每一個票據都得追加下面的信息:一個有效期(lifespan)字段,代表這個票據的最大有效時間;還有一個時間戳(timestamp)字段,代表Charon建立這個票據的時間。因此如今票據信息就變成了

TICKET = {username:ws_address:servicename:lifespan:timestamp} K_server

Euripides:如今當一個服務解碼票據以後,首先檢查下票據裏面的用戶名和地址和用戶發過來的是否一致,接着再用有效期和時間戳字段判斷這個票據是否過時。

Athena:很好,那這個有效期設置多久比較好呢?

Euripides:我也不清楚,設置成大多數工做站的會話時長怎麼樣,即8小時?

Athena:這也就是說,若是我在個人工做站工做超過8小時,我全部的票據都將失效,也包括票據分發票據,因此在8小時後,我必須再次向Charon認證。

Euripides:這個也不是難以接受的吧?

Athena:嗯,也是。那咱們就定下來票據在8小時後過時。如今我有一個新的疑問了,假如我從網絡上覆制了你的票據..

Euripides:哦,Tina,你不會真的這樣作吧,對不對。

Athena:這只是咱們交談的一種假設狀況。如今我複製了你的票據,並等着你退出你的工做站。多是你和醫生有一個約談或者是要參加一個會議,因此你在兩個小時左右就退出了你的工做站。雖然你比較謹慎的在推出時銷燬了你的票據,可是我已經偷取了這些票據,而且在接下來的6個小時裏面它們是無缺可用的,我將有足夠的時間來操做你的文件,以你的名義發送成千上萬的打印任務。

因此說,追加有效期和時間戳的方式對於票據過時後的攻擊是起做用的,可是若是在票據過時前攻擊那。。

Euripides:哦,是的,你是對的。

Athena:我想咱們找到核心問題了。

Euripides:我猜你今天晚上又要忙活了,要去喝些咖啡嗎?

Athena:要的,走

Scene IV

隔天早上,在Euripides的辦公室,Athena敲門進來

Euripides:Tina,一大早就戴着個黑眼圈呀。

Athena:是啊,你知道又一個漫漫長夜。

Euripides:你找到解決問題的方法了嗎?

Athena:我想我找到了。

Euripides:坐下來慢慢說。

Athena:按慣例,首先我要重述下這個問題:票據都有一個有效期-8小時,若是在過時前其餘人偷走了你的票據,那咱們就沒有辦法阻止他了。

Euripides:正是這個問題

Athena:若是咱們把票據設計成不可重複使用,那咱們能夠修復這個問題

Euripides:可是這樣你就不得不在每次想要利用一個網絡服務的時候都去請求一個票據了

Athena:是的,這算是一種粗暴的解決方案。哦,我該怎麼繼續個人論述呢?
好吧,讓咱們從需求的角度再把問題重述一下:一個服務必需要證實如今用票據發起請求的人就是Charon分給票據的那我的。

讓咱們再把認證過程推演一遍,看我可否想出一個合適的方法來表述個人解決方案。

當我想訪問一個特定的服務時,第一步,我在個人工做站上啓動一個客戶端程序,這個客戶端發送三個信息給服務,個人名稱、地址、以及相應的票據。其中票據中包含認證時的用戶名,認證時工做站對應的網絡地址,還包含了票據的過時信息。全部這些信息在返回給客戶端時Charon都用對應服務的密碼進行了加密。

咱們如今的認證模式基於下面的測試:

  • 服務可否解碼對應的票據
  • 票據是否過時
  • 票據中的用戶名和網絡地址是否和票據一塊兒發送的用戶名和地址匹配

這些測試能證實什麼呢?

第一,這個票據是不是Charon分發的,若是票據不能正確解碼,那就不是從真正的Charon過來的。真正的Charon會使用服務對應的密碼加密,而只有Charon和服務知道這個服務的密碼。若是票據能正常解碼器,那服務就能肯定票據是從真正的Charon過來的的,這樣就能防止攻擊者僞造Charon分發票據。

第二,這個票據是否過時,若是過時,服務端就拒絕這個請求,這樣能阻止攻擊者使用舊的票據,由於這些票據頗有可能被偷走了。

第三,檢查票據中的用戶名和網絡地址,若是檢查失敗,說明用戶在使用別人的票據(多是偷偷在用),服務端確定要拒絕這樣的請求。

若是用戶名和地址匹配上,那證實了什麼呢?什麼也沒有,攻擊者能夠從網絡上偷走票據,更改他的工做站地址和用戶名,從而偷竊別人的資源。就像我昨天說的,票據在過時以前是能夠無限制的重用的。它們能被重用是由於服務端沒辦法區分如今請求的用戶是不是票據真正的擁有者。

服務端不能作區分是由於他和用戶之間沒有一個共享的機密信息。打比方來講,我在Elsinore(哈姆雷特里面的城堡)站崗,如今你要來換下我,除非你告訴我正確的暗號,不然我是不會贊成你替換個人,這就是咱們兩個之間須要共享一個機密的例子,這個機密多是某我的爲全部的站崗者想出的暗號。
這就是我昨天晚上想的,爲何不能讓Charon爲票據真正的擁有者和服務生成一個共享的密碼呢?Charon把這個會話密鑰(session key 就是剛說的共享密碼)的一份拷貝發給服務端,再把另外一份拷貝發給用戶,當服務端收到用戶的請求時,他能夠用這個會話密鑰來驗證用戶。

Euripides:等一下,Charon怎麼給服務端和用戶發送這個密鑰呢?

Athena:Charon把會話密鑰做爲返回值的一部分,像這樣:

CHARON REPLY = {sessionkey|ticket} K_user

服務端經過解碼票據來獲取會話密鑰,因此如今票據變成了以下的樣子

TICKET = {sessionkey:username:address:servicename:lifespan:timestamp}K_server

如今當你想要訪問一個服務時,你使用的客戶端程序會構建一個咱們稱之爲「認證對象」(AUTHENTICATOR),這個認證對象中包含你的用戶名和你工做站的網絡地址。客戶端用Charon返回的會話密鑰對認證對象進行加密,就是他向Charon認證時對應的會話密鑰。

AUTHENTICATOR - {username:address} K_session

客戶端構造好認證對象後,和票據一塊兒發送到服務端,這時服務端還不能解碼這個認證對象,由於他尚未拿到回話密鑰,密鑰存放在票據中,因此第一步服務端必須先解碼票據

服務端解碼票據後將獲取下面的信息:

  • 票據有效時間和建立時間
  • 票據擁有者的名字
  • 票據擁有者對應的網絡地址
  • 會話密鑰

服務端先檢查票據是否過時,若是是好的,接着,服務端用會話密鑰解碼對應的認證對象,若是能順利解碼,服務端就會獲取到用戶名和網絡地址,而後服務端把獲取到的用戶名和網絡地址和票據中的對應信息比較,而且再和發送票據、認證對象時一塊兒發送過來的用戶名和網絡地址比較,若是一切都對比正確,則服務端就能夠確認如今發送票據的人確實是票據的擁有者

我認爲會話密鑰-認證對象能解決票據重用帶來的問題

Euripides:可能吧,我仍是有困惑,要想用這個方式,我必須構建服務相應的認證對象

Athena:不,你不只要有認證對象,還要有正確的票據。若是沒有票據只有認證對象是沒有任何意義的,由於沒有解碼票據前你是獲取不到會話密鑰的,而沒有會話密鑰你就無法解碼認證對象。

Euripides:這個我知道,可是你也說了,當一個客戶端程序請求服務端時,他會把認證對象和票據一塊兒發送過去

Athena:是的,我這樣說過

Euripides:若是真是這樣,那怎麼阻止我把認證對象和票據同時偷走呢?我能夠肯定經過程序我能作到這個。若是我能同時偷取到認證對象和票據,這樣在票據過時前我就能夠用這兩個信息,改變我工做站的地址和用戶名來假裝請求了,是否是?

Athena:是的,好失望

Euripides:等等,這沒什麼大不了的。票據在過時以前能夠重複使用,但這並不預示着認證對象也能夠重複使用。假如咱們設計一個方案只容許認證對象使用一次,是否是就沒有問題了

Athena:是的,頗有可能。咱們再討論一下這個過程,客戶端程序構建了一個認證對象,而後把它和票據一塊兒發送給服務端。你把票據和認證對象都複製一份偷走了,可是這個票據和認證對象在你能發給服務端以前已經到達了服務端。若是認證對象只可以使用一次,那你複製下來的票據和認證對象就不起效了,當你嘗試認證時就會失敗

好了,總算放心了,因此如今須要作的事是用一種方式保證認證對象只能使用一次

Euripides:沒有問題,讓咱們在認證對象裏面也存放一個有效期和生成時間。假如每個認證對象的有效期只有幾分鐘。當你想使用一個服務時,你的客戶端程序構建一個認證對象,添加上當前的時間戳,接着把它發送到服務端。

服務端收到票據和認證對象後,先解碼票據獲取會話密鑰,而後用會話密鑰解碼認證對象,接着檢查認證對象是否過時,若是沒有,而且其餘的檢查都經過,服務端經過認證。

假如如今我複製了你的票據和認證對象,爲了使用它們,我須要在幾分鐘內修改好個人工做站網絡和用戶名,這個要求是很高的,我不認爲能作到,除非…

好吧,還有一個潛在的風險,假如我不是在當你向服務端認證時複製票據和認證對象,而是複製Charon發給你的原始數據包,就是你向Charon要票據時它返回給你的數據包

這個數據包,包含了兩份會話密鑰在裏面,一個給你,一個給服務端。給服務端的在票據裏面,我不能拿到,可是另外一個呢,那個你用來生成認證對象的密鑰呢

若是我能拿到這個密鑰,我就能夠構建本身的認證對象,這樣我就能夠攻破這個系統

Athena:這個我昨晚上也想到過,可是我推演了一下獲取票據的過程,發現以這種方式偷取認證對象是不可能的。

你坐在你的工做站前,用kinit程序獲取你的票據分發票據(TGT),kinit須要你的名字,你輸入後,kinit把它發送到Charon。

Charon用你的名字到數據庫中查詢你的密碼,接着建立一個TGT。做爲這個過程的一部分,Charon建立一個你和票據分發服務共享的會話密鑰。Charon把這個密鑰的一份拷貝放到TGT中,把另外一個拷貝放到數據包中,在把這個數據包發送給你以前,Charon會用你的密碼把它加密。

CHARON REPLY = [sessionkey|TGT] K_user

Charon經過網絡把加密後的數據發給你,若是有人偷取了這個數據包,沒有你的密碼他無法解碼這個數據包,也就不能獲取到會話密鑰。

Kinit獲取到這個數據包以後,提示你輸入密碼,若是你輸入了正確的密碼,Kinit就會解碼這個數據包,給你對應的會話密鑰。

客戶端爲票據分發請求建立一個認證對象,並使用會話密鑰對認證對象加密,接着客戶端把這個加密後的認證對象發送給Charon,同時把TGT,你的名字,工做站的網絡地址還有你要訪問的-郵件服務的名稱一塊兒發過去,

票據分發服務(TGS)收到這些信息,(其中TGT和普通的ST,也沒有區別,它就是票據分發服務對應的票據-ST,裏面也是包含了{sessionkey:username:address:servicename:lifespan:timestamp}這些信息,只不過服務名字就是固定的TGS的名字,並用票據分發服務對應的密碼進行了加密),就開始正常的認證檢查,(也是先用本身的密碼解碼TGT,看是否過時,再用裏面的會話密鑰解碼認證對象,驗證用戶名,地址)若是檢查經過,票據分發服務(TGS)就會拿到一個正確的會話密鑰,接着票據分發服務爲你構建一個郵件服務的票據,併爲你和郵件服務建立一個新的共享的會話密鑰。

接下來,票據分發服務會準備一個發往你工做站的票據數據包,這個數據包中包含了剛建立的郵件服務的票據和新建的你和郵件服務共享的會話密鑰,在發送數據包以前,票據分發服務會用你和票據分發服務之間共享的會話密鑰把數據包加密。

如今看下郵件服務的票據包的發送,假若有人在這個數據包在網絡上傳輸的工程中複製了一份,因爲數據包用數據分發服務的會話密鑰加密過,他也得不到裏面的內容,於是不能獲得在數據包中的郵件服務的會話密鑰,沒有這個密鑰,他就不能建立認證對象,從而也不能使用TGS生成的並經過網絡傳輸的郵件服務票據。

因此如今來看,咱們安全了,你認爲呢?

Euripides:可能吧

Athena:可能,你就只能說個這嗎

Euripides:別生氣,這只是對我本身刻薄的說法,你爲這個都搞了大半夜了

Athena:Pthhhhh!

Euripides:好吧,是3/4個晚上,如今,這個系統聽起來能夠接受了,會話密鑰的方式解決了昨晚上我思考的一個問題,一個雙向認證的問題,介意我再說幾分鐘嗎?

Athena:固然

Euripides:你真和藹。昨晚上當會話密鑰和認證對象跳入的大腦時,我嘗試着找到系統的新問題,最後還真找到了一個嚴重問題,接下來我會用一個例子慢慢說明它:

假如說你厭倦了你如今的工做,而且也找到了新的感興趣的想跳槽過去。你想在公司的打印機上打印你的簡歷,使獵頭或者潛在的僱主能注意到你的優勢。

因此你點擊了打印功能,直接把你的簡歷發送給相應的打印機。若是你尚未打印服務的票據,打印客戶端首先會獲取打印服務的票據,再以你的名義把票據發送給服務端,至少在你認爲它是按照這樣的流程來工做的,你並不知道這個任務是否發給了正確的打印機。

假如如今有一些惡意的黑客--你的老闆--有一個轉換系統,利用這個系統,它能把你的請求和票據重定向到他辦公室的打印機上。若是他的這個打印機服務設計的不關心對應的票據和內容,它直接忽略掉票據,並返回給你的工做站一個信息說票據經過驗證,服務端也準備好爲你提供打印服務了。你的打印客戶端發送打印命令給這個假裝的打印機,這樣你的敵人就拿到了你的簡歷。

我用對比的方式重述下這個問題,就是在沒有會話密鑰和認證對象的時候,Charon可以阻止服務端不被錯誤的用戶訪問,可是並不能阻止用戶訪問錯誤的服務端。系統須要一種方式能讓客戶端在發送敏感信息給服務端前先驗證服務端的正確性,也就是說系統必須能雙向認證。

利用會話密鑰,只要你能正確設計客戶端程序,就能夠解決掉這個問題。讓咱們再以打印服務爲例,咱們但願打印客戶端能確認它發的打印服務確實是被正確的打印服務接收到的。

那麼打印客戶端應該這樣作,我輸入一個打印任務和對應的打印文件名-我簡歷的名稱,假如我擁有打印服務的票據和會話密鑰,客戶端程序用會話密鑰構建一個認證對象,把認證對象和票據發給認爲正確的打印機。這時客戶端並無發送要打印的簡歷,他要等待服務端返回信息。
如今正真的打印服務接收到票據和認證對象,首先解碼票據獲取會話密鑰,接着用會話密鑰解碼認證對象,以後作各類認證檢查;

假如認證經過,服務端返回給客戶端一個能證實本身身份的數據包給客戶端,並用會話密鑰把返回的數據包加密。

客戶端收到數據包後會嘗試用會話密鑰解碼數據包。若是數據包正確解碼,而且獲得了正確的服務端返回信息,客戶端就能夠斷定如今返回信息的是正確的打印服務,接着纔會把對應的打印簡歷任務發過去。
這樣假定你的老闆用轉換系統把他的打印機假裝成我想用的那一臺,個人客戶端發送認證對象和票據給他並開始等待返回結果,而假裝的打印機不能生成正確的返回信息,由於它不能解碼票據獲得會話密鑰。這時個人客戶端收不到正確的返回信息,就不會把真正的打印任務發過去,最終客戶端等待超時並退出,雖然個人打印任務沒有完成,但至少個人簡歷沒有出如今敵人的辦公桌上。

你看,咱們有一個堅實的理論依據來實現Charon認證系統了。

Athena:是的。可無論怎麼說,我並不喜歡Charon這個名字

Euripides:你不喜歡,從何時開始的

Athena:我一直都不喜歡,由於這個名字沒有任何意義,我以前跟個人叔叔談起這個事,他建議我用另外一名字,Charon的那只有三個頭的狗

Euripides:哦,你是說「Cerberus」

Athena:注意你的發音,是「Cerberus」

Euripides:呃,是這個名字嗎?

Athena:是的,若是你是個羅馬人,我是一個希臘神,我有一個希臘看門狗,那麼它的名字會讀做「Kerberos」,首字母是K

Euripides:好了好了,不要再扔霹靂了,就用這個名字了,事實上,他有一個漂亮的黑眼圈。如今,再見,Charon,你好,Kerberos。

Afterword

這個對話是在1988年寫的,用來幫助讀者理解爲何Kerberos V4版本設計成這個樣子,這麼多年,它很好的完成了任務。

當我把這個對話整理成HTML後,我驚訝的發現這個文檔也一樣適用於V5版本。雖然不少事情發生了變化,可是協議的核心仍是同樣的。只有兩個地方在V5版本中作了調整。

第一個變化是意識到若是一個黑客用程序來抓取票據和認證對象,並當即將它們發送到服務端,這樣把認證對象的有效期設置成5分鐘並不能有效的阻止這種重放攻擊。

因此在V5版本中,認證對象被真正設計成「只能使用一次」,這經過在服務端設計一個緩存,用來保存最近發過來的認證對象的記錄來實現。攻擊者嘗試偷取認證對象並重用它,即使在5分鐘的窗口期裏,服務端的緩存也能區分出來這個認證對象已經被提交過了。

第二個主要變化是當用戶用Kinit首次從Kerberos獲取服務的票據(TGT)時,在Kerberos把票據返回給客戶端時,票據不須要用用戶的密碼加密。由於這個票據已經用票據分發服務的密碼加密過了,以後用戶用這個票據再向Kerveros請求其餘服務的票據時也是以未加密的形式直接在網絡上傳播的。因此這個地方就沒有必要再用用戶的密碼去進行加密了(返回數據包中的其餘部分如票據會話密鑰等仍是要加密的)

票據分發服務(TGS)也作了一樣的修改,票據分發服務生成的票據,也再也不用票據分發服務對應的會話密鑰加密,由於這個票據已經用服務對應的密碼加密過了。
例如在V4版本中,數據包是下面這樣的

KDC_REPLY = {TICKET, client, server, K_session}K_user
TICKET = {client, server, start_time, lifetime, K_session}K_server

在V5版本中會變成下面的樣子

KDC_REPLY = TICKET, {client, server, K_session}K_user

最終的請求過程以下

固然,Kerberos在V5版本中還加入了其餘的新特性。用戶能夠安全的分發他的票據,從而在其餘的地方使用;用戶也能夠把部分權限授予一個服務器,使這個服務器能夠做爲本身的代理。其餘的新特性包括用更加安全的加密算法代替DES,例如triple-DES。讀者若是想了解更多關於V5和V4之間不一樣點的能夠訪問【Kerberos系統的進化】,做者是 Cliff Neumann 和 Theodore Ts'o。

最後但願你能喜歡關於Kerveros的簡單介紹,祝你在以後的使用中一切順利。

Theodore Ts'o 1997.2

相關文章
相關標籤/搜索