type
status
date
slug
summary
tags
category
icon
password
概述
Kerberos 协议定义客户端如何与网络身份验证服务交互。 客户端从 Kerberos 密钥分发中心 (KDC) 获取票证(ticket),并在建立连接时向服务器出示这些票证。在 Kerberos 协议模式中,每个客户端/服务器连接开始时都会进行身份验证。 客户端和服务器轮流依次执行一系列操作,这些操作用于向连接每一端的一方确认另一端的一方是真实的。 如果身份验证成功,则会话设置完成,从而建立了一个安全的客户端/服务器会话。
当客户端想要与服务器创建安全连接时,客户端首先向 KDC 发送请求,而不是向要访问的服务器发送请求。 KDC 创建唯一 会话密钥供客户端和服务器用来相互进行身份验证。 KDC 有权访问客户端的主密钥和服务器的主密钥。 KDC 使用服务器的主密钥加密服务器会话密钥的副本,并使用客户端的主密钥对客户端的副本进行加密。
基本概念
主体
Kerberos 主体包含以下部分:
dns1.example.com@TEST.COM
- primary: 主体的第一个部分。对于用户,这通常与用户名相同。
- instance(可选):特征的附加信息。此字符串与 primary之间通过一个
/分隔。tux@example.org和tux/admin@example.org可以存在于同一个 Kerberos 系统上,它们被视为不同的主体。
- Realm:指定 Kerberos 的Namespace,不同的kerberos环境可以通过realm区分。通常情况下,Namespace就是大写的域名
KDC
Key Distribution Center(即 KDC), 是 Kerberos 的核心组件,主要由三个部分组成:
- Kerberos Database: 包含了一个 Realm 中所有的 principal、密码与其他信息。(默认:Berkeley DB)
- Authentication Service(AS): 进行用户信息认证,为客户端提供 Ticket Granting Tickets(TGT),包含客户端ID、客户端网络地址、票据有效期以及client/TGS会话密钥
- Ticket Granting Service(TGS): 验证 TGT ,为客户端提供 Service Tickets。 TGT类似于护照,Ticket则是签证,而访问特定的服务则好比出游某个国家。与护照一样,TGT可标识你的身份并允许你获得多个Ticket(签证),每个Ticket对应一个特定的服务,TGT和Ticket同样具有有效期,过期后就需要重新认证
Kerberos原理
在深入了解 Kerberos 原理之前,先介绍一下 Kerberos 协议的几个大前提,帮助大家理解:
- Kerberos 基于 Ticket 实现身份认证,而非密码。如果客户端无法利用本地密钥,解密出 KDC 返回的加密Ticket,认证将无法通过。
- 客户端将依次与 Authentication Service, Ticket Granting Service 以及目标Service进行交互,共三次交互。
- 客户端与其他组件交互是,都将获取到两条信息,其中一条可以通过本地密钥解密出,另外一条将无法解密出。
- 客户端想要访问的目标服务,将不会直接与KDC交互,目标服务通过能否正确解密出客户端的请求来进行认证。
- KDC Database 包含有所有 principal 对应的密码。
- Kerberos 中信息加密方式一般是对称加密(可配置成非对称加密)
Kerberos通信步骤

Kerberos的认证过程可细分为三个阶段:初始验证、获取服务票据和服务验证。第一阶段主要是客户端向KDC中的AS发送用户信息,以请求TGT,然后到第二阶段,客户端拿着之前获得的TGT向KDC中的TGS请求访问某个服务的票据,最后阶段拿到票据(Ticket)后再到该服务的提供端验证身份,然后使用建立的加密通道与服务通信。
初始验证
此过程是客户端向AS请求获取TGT:
客户端向AS发送自身用户信息(如用户ID),该动作通常发生在用户初次登陆或使用kinit命令时
AS检查本地数据库是否存在该用户,若存在则返回如下两条信息:
消息A:使用用户密钥加密的Client/TGS会话密钥,我们称之为SK1。其中用户密钥是通过对该用户在数据库中对应的密码hash生成的消息B:使用TGS的密钥加密的TGT(包含客户端ID、客户端网络地址、票据有效期和SK1)
当客户端收到消息A和B时,它会尝试用本地的用户密钥(由用户输入的密码或kerberos.keytab文件中的密码hash生成)对A进行解密,只有当本地用户密钥与AS中对应该用户的密钥匹配时才能解密成功。对A解密成功后,客户端就能拿到SK1,才能与TGS进行后续的会话,这里就相当于AS对客户端的一次验证,只有真正拥有正确用户密钥的客户端才能有机会与AS进行后续会话。而对于消息B,由于它是由TGS的密钥加密的,故无法对其解密,也看不到其中的内容。
获取服务票据
此过程则是客户端向TGS请求获取访问对应服务的票据:
当客户端要访问某个服务时,会向TGS发送如下两条消息:
消息C:消息B的内容(即加密后的TGT)和服务ID消息D:通过SK1加密的验证器(Authenticator,包括用户ID和时间戳)
TGS收到消息C和D后,首先检查KDC数据库中是否存在所需服务,若存在则用自己的TGS密钥尝试对C中的消息B进行解密,这里也是客户端对TGS的反向认证,只有真正拥有正确密钥的TGS才能对B解密,解密成功后就能拿到其中的SK1,然后再用SK1解密消息D拿到包含用户ID和时间戳的Authenticator,通过比较分别来自C和D的用户ID,如果二者匹配,则向客户端返回如下两条消息:
消息E:通过SK1加密的Client/SS会话密钥,该会话密钥是KDC新生成的随机密钥,用于将来客户端(Client)与服务端(SS)的通信加密,我们称之为SK2消息F:使用服务的密钥加密的client-server票据(Ticket,包含用户ID、用户网络地址、票据有效期和SK2)
之所以要用服务的密钥加密,是因为这个Ticket是给服务端看的,但又需要经过客户端传给服务端,且不能让客户端看到。那么就会有人问,为什么KDC不直接把消息E发送给服务端呢,这样岂不省事?问题就在于网络时延,若分开发送,消息E和F就不能确保同时到达服务端,考虑一个极端情况,KDC与服务之前的网络临时不通了,那么这段时间服务端就无法收到消息E,导致验证失败,而实际上该客户端是有访问权限的。通过公钥加密这种方式巧妙地回避了该问题.客户端收到消息后,尝试用SK1解密消息E,得到Client/SS会话密钥SK2
服务验证
此过程是客户端与服务端相互验证,并通信
客户端向服务端发送如下两条消息:
消息G:即上一步中的消息F——client-server票据消息H:通过SK2加密的新的验证器(Authenticator,包含用户ID和时间戳)
服务端收到消息后,尝试用自己的密钥解密消息G,这里实际上也是客户端对服务端的一次验证,只有真正拥有正确密钥的服务端才能正确解密,从而有机会拿到Ticket中的SK2,然后再用该SK2解密消息H,同TGS一样,对分别来自Ticket和Authenticator中的用户ID进行验证,如果匹配成功则返回一条确认消息:
消息I:通过SK2加密的新时间戳
客户端尝试用SK2解密消息I,得到新时间戳并验证其正确性,验证通过后,客户端与服务端就达到了相互信任,后续的通信都采用SK2加密,就好比建立了一条加密通道。
安装Kerberos客户端(Centos)
参考
- 作者:Ryan Wu
- 链接:https://hexo.fridaylab.top/article/92f11c3b-d92c-4c73-9800-c1709fcbc4b0
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
