19

我想用 Java 中的 Kerberos 实现单点登录,并成功地使用来自 Windows 登录的票证为服务创建票证。不幸的是,我只能在启用注册表项“allowtgtsessionkey”时创建该票证。一旦我禁用它,我就会收到一条异常消息“标识符与预期值不匹配 (906)”。注册表项记录在http://java.sun.com/j2se/1.5.0/docs/guide/security/jgss/tutorials/Troubleshooting.htmlhttp://support.microsoft.com/kb/308339上。

不幸的是,我无法访问将要使用我的应用程序的计算机上的注册表,因此我正在寻找一种无需修改即可执行此操作的方法。当我在 Internet Explorer 或 Mozilla Firefox 中通过 SPNEGO 进行单点登录时,它们会在我的票证缓存中创建一个服务票证,因此肯定有一种方法可以在不设置注册表项的情况下执行此操作。有谁知道如何在 Java 中做到这一点?

谢谢你的帮助,memminger

更新:我放弃了这个问题。Windows 注册表项可防止访问票证缓存中的票证(更准确地说:主题)。Windows 上的 Java 使用自己的 GSSAPI 实现,我想这需要访问票证才能创建服务票证。SSPI Windows API 虽然可以完全访问票证缓存,因此可以创建服务票证。Web 浏览器使用此 API,但 Java 不使用此 API(根据http://java.sun.com/developer/technicalArticles/J2SE/security/#3)。当我在访问过一次网页后在 Firefox 中禁用 SSPI(因此已创建服务票证)时,我仍然可以访问该页面,因此也许命令行工具足以使用 SPPI API 创建服务票证。

对我们来说,这意味着现在我们可以放弃单点登录(这对我们来说是不可接受的),或者我们在应用程序的客户端进行身份验证(因为我们只能读出用户名而不能在服务器),这是一个主要的安全风险。另一个例子是更强大的安全约束如何导致更大的安全漏洞,因为它们变得太复杂而无法使用。

4

4 回答 4

4

如果我误解了你的问题,请原谅我,但是......

SSO 类型系统的要点是客户端直接向(单独的)身份验证服务器进行身份验证,并从中获取票证。然后它将票证传递给它想要使用的目标服务器,每个目标服务器都验证票证对身份验证服务器有效。如果票证被验证,则服务器可以假设客户端仅通过向(受信任的)Kerberos 服务器提供可接受的凭据来获取票证。

在此过程中,任何服务器都不应代表客户端进行身份验证。在这样的系统中,唯一需要知道和验证客户端凭据的服务器是身份验证服务器 - 没有其他服务器需要访问此信息。这样,客户端只需一次身份验证交换即可对许多服务器进行身份验证,并且凭据不会因存储在多个服务器上或可供多个服务器访问而面临风险。

听起来您的实现正在正常工作 - 身份验证应该发生在应用程序的客户端,这是正确的,没有安全风险。

于 2010-02-28T05:51:08.033 回答
2

您是否尝试过在 Java 6 中设置 sun.security.jgss.native?SSPI 不是 Windows 的“本机”界面吗?

于 2010-07-08T06:40:04.387 回答
1

您可以通过JNA访问本机 SSPI API 。有关示例,请参阅Apache HC 库中的WAFFLEWindowsNegotiateScheme中的WindowsAuthProviderImpl 。

于 2015-10-05T09:16:17.543 回答
1

JDK 13 中引入了对 Windows SSPI 的本机支持,后来也向后移植到了 JDK 11。您至少需要使用 Java 11.0.10。当使用 JDK 对 SSPI 的支持时,不再需要摆弄allowtgtsessionkey注册表项,也不需要使用 JNA 或 Waffle。

你需要设置

-Dsun.security.jgss.native=true

让它工作。

如果您的 JDK 版本包含sspi_bridge.dllbin目录中命名的文件,您可以识别它是否支持 SSPI。

参考:

JDK-6722928

于 2021-11-07T09:14:47.747 回答