[英]Tomcat 9.x.x Client Authentication using X.509 Certificates
我正在使用 Tomcat 9.0.19 并尝试为特定的 Web 应用程序启用基于 X.509 证书的客户端身份验证(AKA I&A)。
总之,Tomcat 适用于通过单向 TLS 启用基本 I&A 的应用程序。 当访问具有基于证书的 I&A 的 Web 应用程序时,Tomcat 似乎不会在发送 Server Hello Done 之前请求客户端证书作为 Server Hello 消息的一部分,并且稍后无法通过身份验证检查:
02-Jan-2020 13:00:40.371 FINE [https-jsse-nio-443-exec-10] org.apache.catalina.authenticator.SSLAuthenticator.doAuthenticate 查找证书 02-Jan-2020 13:00:40.830 FINE https-jsse-nio-443-exec-10] org.apache.catalina.authenticator.SSLAuthenticator.doAuthenticate 此请求中不包含证书
在 Wireshark 中追踪 TLS 流程并看到了 TLS 1.2 握手。 交换加密数据后不久,Tomcat 会发送“加密警报”消息并关闭套接字。 尝试从浏览器联系 Tomcat,执行 GET。 浏览器没有提示我选择证书,这似乎也指向 Tomcat 没有从浏览器请求它。
任何帮助将不胜感激!
更多细节:
我们有一组 Tomcat 和客户端的证书,由中间 CA 颁发,由根 CA 签名(颁发)。 双方(客户端和服务器)以及其中包含正确证书/密钥的密钥库都已设置信任库。 Web 应用程序设置为需要证书 I&A (web.xml):
<security-constraint>
<web-resource-collection>
<web-resource-name>All by default</web-resource-name>
<url-pattern>/*</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>OTService</role-name>
</auth-constraint>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
<login-config>
<auth-method>CLIENT-CERT</auth-method>
<realm-name>certificate</realm-name>
</login-config>
OTService 角色与单个用户帐户一起在 Tomcat-Users.xml 中设置:
现在,server.xml 中的连接器配置如下:
<Connector port="443" protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="100" SSLEnabled="true" scheme="https" secure="true">
<SSLHostConfig>
<Certificate certificateKeystoreFile="/apache-tomcat-9.0.19/conf/km/keyStore.jks"
certificateKeystorePassword="PASSWORD"
certificateKeyAlias="tomcat"
type="RSA" />
truststoreFile="/apache-tomcat-9.0.19/conf/km/trust_store.jks"
truststorePass="PASSWORD"
truststoreType="JKS"
certificateVerification="required"
clientAuth="true"
protocols="TLSv1.2"
</SSLHostConfig>
</Connector>
为什么Tomcat不会请求客户端证书的任何想法?
当你有:
<Connector ...>
<SSLHostConfig>
<Certificate A=1 B=2 C=3 />
D=4 E=5 F=6
</SSLHostConfig>
</Connector>
那么 A、B、C 是 Certificate 对象的属性,但 D、E、F 不是 SSLHostConfig 对象的属性——它们是不同的 XML内容。 需要在标签中放入属性:
<Connector ... >
<SSLHostConfig certificateVerification="required" truststoreFile=... >
<Certificate ...keystore... />
</SSLHostConfig>
</Connector>
并且根据需要在初始握手时执行证书请求(对我来说,在 tomcat 9.0.14 上测试过)。
我发现的第一个问题是 Tomcat 忽略了信任库的 Connector->SSLHostConfig 设置,并且无论如何都使用了 JRE 默认信任库。 我发现它的方法是让浏览器将协商的 TLS 会话密钥保存到文件 (Google SSLKEYLOGFILE),然后配置 Wireshark 以使用该文件,捕获浏览器-Tomcat 会话,然后能够以明文形式查看每条消息。
接下来,我发现 Tomcat 实际上是在请求客户端证书。但是它发送的接受的根 CA 列表来自默认的 JRE cacerts 文件,而不是来自 truststoreFile 属性指定的文件。 通过将 setenv.sh 文件添加到具有 Java 属性的 Tomcat bin 目录以覆盖默认信任存储位置,可以让 Tomcat 全面使用不同的文件。
现在,我在做生意,浏览器能够完成 TLS 握手,但随后身份验证和授权步骤失败了。 我终于确定了提供证书的正确方法。 tomcat_users.xml 文件中的主题字段不是“CN=OU Client, OU=Control Systems, O=IoTOY, L=Scottsdale, S=AZ , C=US”,而是“CN=OU Client, OU=Control Systems, O =IoTOY,L=斯科茨代尔, ST=AZ ,C=US”。 最后,我有 2-way TLS 工作。
要记住的一件事是,如果在 Tomcat 上运行的任何东西尝试通过 TLS 连接到另一个使用商业 CA 证书的系统,它将失败,因为您现在使用的信任库没有商业根 CA 的证书。 修复它的一种方法是制作默认 JRE cacerts 文件的副本,并将特定于系统的 CA 证书添加到其中,并从上面提到的 setenv.sh 文件中指向它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.