且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

“检测到 GSSException 有缺陷的令牌"- 尝试使用 Kerberos 对在 Windows 上运行的 Tomcat 进行身份验证时

更新时间:2023-01-17 08:08:26

错误Defective token detected"可能意味着 标记被检测到.如果 失败 - 否则 Web 服务器未指示时.在 操作系统上,IE 网络浏览器就可以了(和 Firefox,如果配置正确)基本上是说,如果您不使用 Kerberos,我将向您发送一个 NTLM 令牌.服务器回复不可能",我什至不知道 NTLM,所以我说你发送给我的东西有缺陷.由于您似乎是第一次进行设置,因此您可能没有为 Kerberos 失败时配置任何回退机制(例如 NTLM),因此,该错误消息.我们通过了解 Kerberos 失败的原因来解决这个问题.我想我在与 SPN 和可信站点相关的两个地方看到了您问题中失败的原因.即使您解决了这两个项目,还有第三个和第四个原因可能会继续失败,这与加密有关.

The error "Defective token detected" likely means that an ntlm token was detected. That’s what the Negotiate mechanism uses inside popular web browsers if kerberos fails - when not instructed by the web server otherwise.  On windows operating systems, the IE web browser on it (and Firefox, if configured correctly) basically says, if you won’t do Kerberos, I’m going to send you an NTLM token.  And the server replies "no way" I don’t even know NTLM so I’m calling what you sent me defective.  Since you seem to be setting this up for the first time, you likely did not configure any fallback mechanism (such as NTLM) for when Kerberos fails, therefore, that error message. We solve this by understanding why Kerberos is failing.  I think I see the reason for the failure in your question, in two places, related to SPNs and Trusted Sites. Even if you resolve those two items, there is a third reason and fourth reason why it could continue to fail, related to encryption.

  1. HTTP 服务的 没有与浏览器输入的 URL 匹配.这些需要匹配,否则 Kerberos 将失败.要工作,浏览器应该使用:http://kerberos500.nickis.life:8080,而不是 http://nickis.life:8080.我说的是基于我在你的 中看到的创建语法.因为您已将 SPN 编码为:HTTP/kerberos500.nickis.life@NICKIS.LIFE.这就是您需要使用 http://kerberos500.nickis.life:8080 的原因.当您告诉浏览器转到 http://nickis.life:8080 时,浏览器将不知道如何访问您的 Web 服务.使用该*** URL,浏览器假定它需要找到在您的 Active Directory 上运行的 Web 服务(假设只有 nickis.life 的任何东西都在域控制器上运行).出于安全原因,DC 不应运行网络服务器.
  2. 您需要在 IE 设置下将 http://kerberos500.nickis.life 添加为受信任站点.或者, *.nickis.life 也可以.(您将其称为受信任的角色,而实际上称为受信任的站点).
  3. 您将 Kerberos 加密类型限制为 DES-CBC-MD5.从 Windows Server 2008 Active Directory R2 开始,默认情况下禁用 DES.如今,DES 是一种过时且普遍不安全的加密类型.使用 AES128 更好,甚至更好,使用 AES256.您可以按照下面的示例重新生成密钥表来解决此问题.
  4. 在 AD 用户帐户 kerberos500 中,转到帐户"选项卡,滚动到底部,然后选中 DES、AES 128 和 AES 256 的所有框,然后您就可以退出对话框了.即使您按照上面的步骤进行了所有操作,也必须选中这些框,否则 Kerberos 身份验证仍然会失败.
  1. The spn for the HTTP service does not match the URL entered by the browser. These need to match, otherwise Kerberos will fail. To work, the browser should be using: http://kerberos500.nickis.life:8080, not http://nickis.life:8080. I say that based on what I saw in your keytab creation syntax. In that you’ve coded the SPN as such: HTTP/kerberos500.nickis.life@NICKIS.LIFE. That’s why you need to use http://kerberos500.nickis.life:8080. The browser won’t know how to get to your web service when you tell it to go to http://nickis.life:8080. With that top URL, the browser assumes it needs to find a web service running on your Active Directorydomaincontroller (anything with just nickis.life is assumed to run on the Domain Controller). DCs should never run web servers for security reasons.
  2. You’ll need to add http://kerberos500.nickis.life as a Trusted Site under IE settings. Alternatively, *.nickis.life would work as well. (You called it Trusted Roles, when it’s actually called Trusted Sites).
  3. You are restricting the Kerberos encryption type to DES-CBC-MD5. Starting with Windows Server 2008 Active Directory R2, DES is disabled by default. DES is an outdated and generally insecure encryption type these days. Much better to use AES128 or even better, AES256. You can fix that by re-generating the keytab per my example below.
  4. In the AD user account kerberos500, go to the Account tab, scroll to the bottom, and check all the boxes for DES, AES 128, and AES 256, and OK you’re way out of the dialog boxes. You must check these boxes even if you did everything right above, or else Kerberos authentication will still fail.

如何正确地重新生成密钥表:当您计划创建与该用户帐户相关联的密钥表时,不应运行 setspn -a 命令向 AD 用户添加 SPN.原因是因为 keytab 创建命令将 SPN 作为命令的一部分添加到用户帐户.如果您的方案在按照我上面的建议之后不起作用,那么您需要通过 setspn -D 删除 SPN,如下所示:

How to properly re-generate the keytab: You should not run the setspn -a command to add an SPN to an AD user whenever you are planning to make a keytab associated with that user account.  The reason why is because the keytab creation command adds the SPN to the user account as part of the command.  If your scenario doesn’t work after following my advice above, then you’ll need to remove the SPN via setspn -D like below:

setspn -D HTTP/nickis.life@NICKIS.LIFE kerberos500

之后重新生成密钥表,我唯一的改变是我告诉它使用所有加密类型.客户端和服务器将在身份验证过程中就最强的共同点达成一致.

And the re-generate the keytab afterwards, my only change is that I told it to use all encryption types. The client and server will agree on the strongest common one during the authentication process. 

ktpass -out c:UsersAdministratorkerberos500.keytab -princ HTTP/nickis.life@NICKIS.LIFE -mapUser kerberos500 -mapOp set -pass XXXXpasswordforkerberos500userXXXX -crypto ALL -pType KRB5_NT_PRINCIPAL


然后用新的密钥表替换旧的密钥表.有关密钥表的其他深入信息,您可以在我的关于如何在此处创建 Kerberos 密钥表的技术文章中阅读更多信息:Kerberos Keytabs – 解释.我经常返回并根据我在此论坛中看到的问题对其进行编辑.


Then replace the old keytab with the new one. For additional in-depth information on keytabs, you can read more from my technical article on how to create Kerberos keytabs here: Kerberos Keytabs – Explained. I frequently go back and edit it based on questions I see here in this forum.

顺便说一下,HTTP/kerberos500.nickis.life 是服务主体,而不是您在问题中所写的用户主体.我只使用 Web 浏览器在这样的 HTTP 场景中测试 Kerberos,我不使用 cURL.

By the way, HTTP/kerberos500.nickis.life is a service principal, not a user principal as you wrote in your question. I only use web browsers to test Kerberos in HTTP scenarios like this one, I don’t use cURL.

我很肯定,如果您认真完成我上面强调的所有四点,您就会解决这个问题.

I am positive if you diligently go through all four points I’ve highlighted above, you will resolve this problem.

此答案假设您在具有完全限定域名 kerberos500.nickis.life 的主机上运行 HTTP 服务.如果你没有这个名字的主机,我的答案会略有变化.如果有的话请告诉我.

This answer assumes you have an HTTP service running on a host with the fully-qualified domain name of kerberos500.nickis.life. If you don't have such a host with that name, my answer will slightly change. Please let me know if any.

使用http://nickis.life的URL来达到认证的目的:8080,那么您可以继续使用您已经创建的相同密钥表.

To achieve the objective of authentication using the URL of http://nickis.life:8080, then you may keep on using the same keytab you already created.

在 AD 帐户 NICKISkerberos500 上,转到帐户"选项卡,滚动到底部,然后选中为此帐户使用 Kerberos DES 加密类型"框.

On the AD account NICKISkerberos500, go to the Account tab, scroll to the bottom, and check the box for "Use Kerberos DES encryption types for this account".

然后通过组策略在 AD 域级别启用 DES 加密本身.为此,请执行以下操作:

Then enable DES encryption itself at the AD domain level via Group Policy. To do that, conduct the following:

  1. 打开组策略管理控制台 (GPMC).
  2. 编辑默认域策略 GPO.(改为创建新的域级 GPO 并对其进行编辑更安全,但这取决于您).
  3. 导航到计算机配置">策略">Windows 设置">安全设置">本地策略">安全选项">网络安全:配置 Kerberos 允许的加密类型"并选中 DES_CBC_MD5 和 DES_CBC_MD5 的两个复选框.重要提示:在同一个组策略中,还要确保 RC4、AES128 和 AES256 的复选框也被选中.这些加密类型不会用于您网站的票证,但它们将用于域中的所有其他内容.好的,您已退出对话框并关闭 GPMC.
  4. 在 DC 服务器和客户端上运行gpupdate/force"命令.
  5. 在客户端上运行klist purge"以清除所有 Kerberos 票证.
  6. 在网络浏览器中,清除缓存并删除所有 cookie.
  7. 确保 DC 服务器允许端口 8080 TCP 入站.
  8. 再试一次.

参考:Kerberos 支持的加密类型的 Windows 配置

编辑 3:避免在 同一台机器.即使您已正确完成其他所有操作,这也是获得缺陷令牌错误"的经典方法.

EDIT 3: Avoid running Kerberos KDC (the DC), client and server on the same machine. That is a classic recipe for getting the "Defective token error" even if you've done everything else right.

编辑 4:(由 OP 验证的最终更新):查看新的 ktpass 密钥表创建输出,我看到了:目标域控制器:WIN-OVV6VHBGIB8.fusionis.life.现在,keytab 中定义的 SPN 是 HTTP/kerberos500.nickis.life.AD 域名与您定义的 SPN 不同,因此除非您在这些域之间设置了某种信任,否则这将不起作用.如果您没有信任,则需要改用 HTTP/kerberos500.fusionis.life 的 SPN.

EDIT 4: (Final update which was verified by the OP): Looked at the new ktpass keytab creation output, and I saw this: Targeting domain controller: WIN-OVV6VHBGIB8.fusionis.life. Now, the defined SPN in the keytab is HTTP/kerberos500.nickis.life. The AD domain name is different from the SPN you defined, so this is not going to work unless you have some kind of trust setup between these domains. If you don't have a trust, you need to use an SPN of HTTP/kerberos500.fusionis.life instead.