Kerberos - 找不到适当类型的密钥来解密 AP REP - RC4 与 HMAC

Posted

技术标签:

【中文标题】Kerberos - 找不到适当类型的密钥来解密 AP REP - RC4 与 HMAC【英文标题】:Kerberos - Cannot find key of appropriate type to decrypt AP REP - RC4 with HMAC 【发布时间】:2015-10-30 20:34:06 【问题描述】:

我正在尝试使用 Kerberos/SpNego 为 Java WebApp 设置 SSO。 我正在使用:

Java 1.7u67 org.springframework.security.kerberos 1.0.0.RELEASE 活动目录 Linux 上的 Tomcat 7

克服How to configure kerberos on Tomcat/linux server? 中描述的问题后,我现在遇到以下错误:

org.springframework.security.authentication.BadCredentialsException: Kerberos validation not succesful
        at org.springframework.security.kerberos.authentication.sun.SunJaasKerberosTicketValidator.validateTicket(SunJaasKerberosTicketValidator.java:70) ~[spring-security-kerberos-core-1.0.0.RELEASE.jar:1.0.0.RELEASE]
        at org.springframework.security.kerberos.authentication.KerberosServiceAuthenticationProvider.authenticate(KerberosServiceAuthenticationProvider.java:64) ~[spring-security-kerberos-core-1.0.0.RELEASE.jar:1.0.0.RELEASE]
        at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:156) ~[spring-security-core-3.2.7.RELEASE.jar:3.2.7.RELEASE]
        at org.springframework.security.kerberos.web.authentication.SpnegoAuthenticationProcessingFilter.doFilter(SpnegoAuthenticationProcessingFilter.java:145) ~[spring-security-kerberos-web-1.0.0.RELEASE.jar:1.0.0.RELEASE]
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.2.7.RELEASE.jar:3.2.7.RELEASE]
        at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:199) [spring-security-web-3.2.7.RELEASE.jar:3.2.7.RELEASE]
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.2.7.RELEASE.jar:3.2.7.RELEASE]
        at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:110) [spring-security-web-3.2.7.RELEASE.jar:3.2.7.RELEASE]
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.2.7.RELEASE.jar:3.2.7.RELEASE]
        at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50) [spring-security-web-3.2.7.RELEASE.jar:3.2.7.RELEASE]
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.1.6.RELEASE.jar:4.1.6.RELEASE]
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.2.7.RELEASE.jar:3.2.7.RELEASE]
        at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87) [spring-security-web-3.2.7.RELEASE.jar:3.2.7.RELEASE]
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.2.7.RELEASE.jar:3.2.7.RELEASE]
        at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192) [spring-security-web-3.2.7.RELEASE.jar:3.2.7.RELEASE]
        at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160) [spring-security-web-3.2.7.RELEASE.jar:3.2.7.RELEASE]
        at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:344) [spring-web-4.1.6.RELEASE.jar:4.1.6.RELEASE]
        at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:261) [spring-web-4.1.6.RELEASE.jar:4.1.6.RELEASE]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) [catalina.jar:7.0.55]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) [catalina.jar:7.0.55]
        at org.lightadmin.core.view.TilesContainerEnrichmentFilter.doFilterInternal(TilesContainerEnrichmentFilter.java:40) [lightadmin-1.2.0.RC1.jar:1.2.0.RC1]
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.1.6.RELEASE.jar:4.1.6.RELEASE]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) [catalina.jar:7.0.55]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) [catalina.jar:7.0.55]
        at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77) [spring-web-4.1.6.RELEASE.jar:4.1.6.RELEASE]
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.1.6.RELEASE.jar:4.1.6.RELEASE]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) [catalina.jar:7.0.55]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) [catalina.jar:7.0.55]
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220) [catalina.jar:7.0.55]
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122) [catalina.jar:7.0.55]
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501) [catalina.jar:7.0.55]
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171) [catalina.jar:7.0.55]
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103) [catalina.jar:7.0.55]
        at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950) [catalina.jar:7.0.55]
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116) [catalina.jar:7.0.55]
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408) [catalina.jar:7.0.55]
        at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1070) [tomcat-coyote.jar:7.0.55]
        at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:611) [tomcat-coyote.jar:7.0.55]
        at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:316) [tomcat-coyote.jar:7.0.55]
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) [na:1.7.0_67]
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) [na:1.7.0_67]
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-coyote.jar:7.0.55]
        at java.lang.Thread.run(Thread.java:745) [na:1.7.0_67]
Caused by: java.security.PrivilegedActionException: null
        at java.security.AccessController.doPrivileged(Native Method) ~[na:1.7.0_67]
        at javax.security.auth.Subject.doAs(Subject.java:415) ~[na:1.7.0_67]
        at org.springframework.security.kerberos.authentication.sun.SunJaasKerberosTicketValidator.validateTicket(SunJaasKerberosTicketValidator.java:67) ~[spring-security-kerberos-core-1.0.0.RELEASE.jar:1.0.0.RELEASE]
        ... 42 common frames omitted
Caused by: org.ietf.jgss.GSSException: Failure unspecified at GSS-API level (Mechanism level: Invalid argument (400) - Cannot find key of appropriate type to decrypt AP REP - RC4 with HMAC)
        at sun.security.jgss.krb5.Krb5Context.acceptSecContext(Krb5Context.java:788) ~[na:1.7.0_67]
        at sun.security.jgss.GSSContextImpl.acceptSecContext(GSSContextImpl.java:342) ~[na:1.7.0_67]
        at sun.security.jgss.GSSContextImpl.acceptSecContext(GSSContextImpl.java:285) ~[na:1.7.0_67]
        at sun.security.jgss.spnego.SpNegoContext.GSS_acceptSecContext(SpNegoContext.java:875) ~[na:1.7.0_67]
        at sun.security.jgss.spnego.SpNegoContext.acceptSecContext(SpNegoContext.java:548) ~[na:1.7.0_67]
        at sun.security.jgss.GSSContextImpl.acceptSecContext(GSSContextImpl.java:342) ~[na:1.7.0_67]
        at sun.security.jgss.GSSContextImpl.acceptSecContext(GSSContextImpl.java:285) ~[na:1.7.0_67]
        at org.springframework.security.kerberos.authentication.sun.SunJaasKerberosTicketValidator$KerberosValidateAction.run(SunJaasKerberosTicketValidator.java:162) ~[spring-security-kerberos-core-1.0.0.RELEASE.jar:1.0.0.RELEASE]
        at org.springframework.security.kerberos.authentication.sun.SunJaasKerberosTicketValidator$KerberosValidateAction.run(SunJaasKerberosTicketValidator.java:152) ~[spring-security-kerberos-core-1.0.0.RELEASE.jar:1.0.0.RELEASE]
        ... 45 common frames omitted
Caused by: sun.security.krb5.KrbException: Invalid argument (400) - Cannot find key of appropriate type to decrypt AP REP - RC4 with HMAC
        at sun.security.krb5.KrbApReq.authenticate(KrbApReq.java:273) ~[na:1.7.0_67]
        at sun.security.krb5.KrbApReq.<init>(KrbApReq.java:144) ~[na:1.7.0_67]
        at sun.security.jgss.krb5.InitSecContextToken.<init>(InitSecContextToken.java:108) ~[na:1.7.0_67]
        at sun.security.jgss.krb5.Krb5Context.acceptSecContext(Krb5Context.java:771) ~[na:1.7.0_67]
        ... 53 common frames omitted

但是似乎钥匙应该在那里,因为在启动应用程序时我得到了以下调试:

  Debug is  true storeKey true useTicketCache false useKeyTab true doNotPrompt true ticketCache is null isInitiator false KeyTab is /opt/pksvc/tomcat_edl/current/conf/TestSpnego.keytab refreshKrb5Config is false principal is TestSpnego@MYREALM.DE tryFirstPass is false useFirstPass is false storePass is false clearPass is false
principal is TestSpnego@MYREALM.DE
Will use keytab
>>> KeyTabInputStream, readName(): MYREALM.DE
>>> KeyTabInputStream, readName(): HTTP
>>> KeyTabInputStream, readName(): lxdetstpksvc01.mydomain.de
>>> KeyTab: load() entry length: 83; type: 23
Ordering keys wrt default_tkt_enctypes list
Java config name: /opt/pksvc/tomcat_edl/current/conf/krb5.conf
Loaded from Java config
default etypes for default_tkt_enctypes: 23.
Commit Succeeded

所以 enctype 23 = RC4 with HMAC 是 KeyTab 条目的类型和默认的 enctype。 我还可以看到浏览器使用此 enctype 发送了一个令牌(我从以下内容中删除了二进制部分):

Ticket  TicketTypeTktVno=5,Realm=MYREALM.DE,Sname=HTTP/lxdetstpksvc01.mydomain.de,EncPart=EncryptedDataEtype=23,Kvno=4,Cipher=binary[...  352 16728   KerberosV5.TicketType   
Authenticator   EncryptedDataEtype=23,Kvno=nothing,Cipher=binary[...   17080   2872    KerberosV5.EncryptedData    

所以一切似乎都是 encytpe 23(带有 HMAC 的 RC4)。当我查看代码时,我发现 KrbApReq 使用的 sun.security.krb5.EncryptionKey (在上面的堆栈中引发错误)确实不仅在比较 enctype,而且还在比较版本。所以我想这在我的情况下一定是错的。 在上面的票证中,EncryptedData 的 Kvno=4 和 Authenticator EncryptedData 的 Kvno=nothing。这些应该匹配吗?

我该如何解决这个问题?这是否受 keytab 生成的影响?

【问题讨论】:

tomcat.apache.org/tomcat-7.0-doc/windows-auth-howto.html 上的 kvno 信息看起来很有希望。我会试试的。 请问您是如何在浏览器中查看票证的,我遇到了类似的问题并尝试了您的解决方案,但没有成功。 ***.com/questions/60380712/… 【参考方案1】:

我遇到了同样的错误,因为 keytab 文件是使用错误的/crypto 配置生成的。

在 GSS-API 级别未指定失败(机制级别:无效参数 (400) 找不到适当类型的密钥来解密 AP-REQ - RC4 与 HMAC)

使用/crypto ALLktpass 命令生成一个新的keytab 文件:

ktpass /out "server.keytab" /crypto ALL /princ HTTP/server@REALM /mapuser KERBEROS_SERVICEUSER /pass PASSWORD /ptype KRB5_NT_PRINCIPAL

HTTP/server@REALMKERBEROS_SERVICEUSERPASSWORD 替换为相应的值。

【讨论】:

【参考方案2】:

如果您使用的是 Spring Boot,请注意如何指定 keytab 文件。

请注意,classpath: 将在您运行 spring-boot:run 时起作用 但是,当您运行 java -jar xyz.jar 时它不会,因为 JAAS 无法从类路径中读取它。 所以请在指定 keytab 文件路径时首选file:(这是您使用 docker 打包和运行应用程序时的典型情况)

【讨论】:

【参考方案3】:

我在 4 小时内一直在努力解决这个问题

在 jaas 文件中设置为 true 的参数“storeKey”解决了这个问题

【讨论】:

这对我也有用。而且在对kerberos遗留源代码进行深度调试之后,其实这个flag是有效果的。想知道为什么有人不赞成这个。【参考方案4】:

spring 安全配置中的服务主体与 keytab 中的服务主体不同(来自 ktpass 的参数 /princ)。

在我的情况下,它们是相同的,但参数 /princ 不正确。 HTTP 和域部分必须为大写。

正确示例:

HTTP/service.example.lan@EXAMPLE.LAN

不正确的例子:

http/service.example.lan@Eexample.lan

【讨论】:

【参考方案5】:

在我的例子中,服务器的 jaas 配置文件需要将参数“storeKey”设置为 true。

【讨论】:

【参考方案6】:

原来上面的错误是由两个问题引起的:

    spring 配置中的服务主体错误。它是 lxdetstpksvc01.mydomain.de@MYREALM.DE,但是 HTTP/lxdetstpksvc01.mydomain.de@MYREALM.DE 是正确的。

    keytab 中的 Kvno 与存储在 keytab 中的 Kvno 不同 活动目录。如上所述 https://tomcat.apache.org/tomcat-7.0-doc/windows-auth-howto.html 每次执行 ktpass 时,Active Directory 都会提高 Kvno。 但是我找不到值(msDS-KeyVersionNumber) 它在我们的 AD 中,只能从请求中获取。

总结了“找不到适当类型的密钥来解密...”错误可能是由以下问题之一引起的:

    spring 安全配置中的服务主体与 keytab 中的服务主体不同(来自 ktpass 的参数 /princ)。 没有用于 AD 发送票证的 enctype 的密钥(来自 ktpass 的参数 /crypto 并在 krb5.conf/permitted_enctypes+default_tkt_enctypes 中设置)。 票证中的 Kvno 与 keytab 中的 Kvno 不同(来自 ktpass 的参数 /kvno)。 keytab 的路径错误(请参阅 Xavier Portebois 的回答) 进程没有读取keytab的权限(见user7610的评论)

【讨论】:

其实有办法偷看AD中主机的msDSKeyVersionNumber属性,见serverfault.com/questions/601270【参考方案7】:

如果您使用 Active Directory 作为 KDC 并且 keytab 用户配置的加密设置与您的 keytab 使用的不同,也可能会引发此问题。在我的情况下,配置了 AES 128,我期待 AES 256。在 AD 中简单更改配置即可解决问题。

【讨论】:

这是我回答中第二种情况的示例 - 票证中的 encytpe 和 keytab 不匹配 - 不是吗? 有点。我在调试时不清楚的是,我应该修复 AD 计算机中支持的 enctype 和有问题的 AD 服务用户。实际上这篇文章比你的回答更清楚了:posts.specterops.io/kerberoasting-revisited-d434351bd4d1【参考方案8】:

我们还收到了Invalid argument (400) - Cannot find key of appropriate type to decrypt ... 错误。

如果 keytab 的路径错误(在我们的例子中,我们忘记了那里有一个 docker 卷映射),这可以简单地抛出。

所以,请确保 keytab 路径是正确的,因为这可能会引发这个奇怪的异常。

【讨论】:

当您的进程没有读取密钥表文件的权限时,您也会看到这一点。

以上是关于Kerberos - 找不到适当类型的密钥来解密 AP REP - RC4 与 HMAC的主要内容,如果未能解决你的问题,请参考以下文章

Kerberos:应用服务器如何解密服务票据?

重用认证密钥对加密和解密数据

找不到存储在数据集中的类型的编码器。尽管提供了适当的隐式,但错误[重复]

Hadoop Kerberos:hdfs 命令“找不到任何 Kerberos tgt”,即使我使用 kinit 获得了一张票

解决 ssh 找不到对应主机密钥类型

SSPI 提供程序:在 Kerberos 数据库中找不到服务器