认证系统设计经典会话

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

相关文章
相关标签/搜索