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 协议的几个大前提,帮助大家理解:
  1. Kerberos 基于 Ticket 实现身份认证,而非密码。如果客户端无法利用本地密钥,解密出 KDC 返回的加密Ticket,认证将无法通过。
  1. 客户端将依次与 Authentication Service, Ticket Granting Service 以及目标Service进行交互,共三次交互。
  1. 客户端与其他组件交互是,都将获取到两条信息,其中一条可以通过本地密钥解密出,另外一条将无法解密出。
  1. 客户端想要访问的目标服务,将不会直接与KDC交互,目标服务通过能否正确解密出客户端的请求来进行认证。
  1. KDC Database 包含有所有 principal 对应的密码。
  1. Kerberos 中信息加密方式一般是对称加密(可配置成非对称加密)

Kerberos通信步骤

notion image
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)

参考

WindowDNS使用GSS-TSIG协议初识OAuth2.0协议
  • Twikoo