如何从 Java 中的休息请求中检索客户端证书
How to retrieve client certificate from rest request in Java
我在 Java
中将 Jersey
用作 REST
服务器,将 Jetty
用作 Web 服务器。我有 self signed
个证书。我想从收到的 HTTP 请求中获取客户端证书详细信息。如何获取HttpServletRequest
的信息?
一种方法:
X509Certificate certs[] = (X509Certificate[])httpRequest.getAttribute("javax.servlet.request.X509Certificate");
这样对吗?这导致异常,
Error [Ljava.lang.Object; cannot be cast to [Ljava.security.cert.X509Certificate
我应该添加任何额外的 JAR
吗?或者有什么办法可以获取客户端证书的详细信息?
我也遇到了,
httpRequest.getHeader("ssl_client_cert");
这两种方式似乎都不适合我。如何获取详情?
首先,确保处理 SSL/TLS 的 ServerConnector。
接下来,该 ServerConnector 应该有一个 SslConnectionFactory,其中配置了一个 HttpConfiguration 对象。
该 HttpConfiguration 对象应添加 SecureRequestCustomizer。
用嵌入式码头的说法,它看起来像这样...
// SSL Context Factory
SslContextFactory sslContextFactory = new SslContextFactory();
sslContextFactory.setKeyStorePath("/path/to/keystore");
sslContextFactory.setKeyStorePassword("password");
sslContextFactory.setKeyManagerPassword("secret");
sslContextFactory.setTrustStorePath("/path/to/keystore");
sslContextFactory.setTrustStorePassword("password");
// SSL HTTP Configuration
HttpConfiguration https_config = new HttpConfiguration(http_config);
https_config.addCustomizer(new SecureRequestCustomizer()); // <-- THIS LINE
// SSL Connector
ServerConnector sslConnector = new ServerConnector(server,
new SslConnectionFactory(sslContextFactory,HttpVersion.HTTP_1_1.asString()),
new HttpConnectionFactory(https_config));
sslConnector.setPort(8443);
server.addConnector(sslConnector);
如果您在独立 Jetty 上使用 ${jetty.home}
和 ${jetty.base}
拆分,那么您需要检查配置中是否存在 jetty-ssl.xml
...
$ cd /path/to/my-jetty-base
$ java -jar /path/to/jetty-home/start.jar --list-config
Java Environment:
-----------------
java.home = /Library/Java/JavaVirtualMachines/jdk1.8.0_202.jdk/Contents/Home/jre (null)
java.vm.vendor = Oracle Corporation (null)
java.vm.version = 25.202-b08 (null)
java.vm.name = Java HotSpot(TM) 64-Bit Server VM (null)
java.vm.info = mixed mode (null)
java.runtime.name = Java(TM) SE Runtime Environment (null)
java.runtime.version = 1.8.0_202-b08 (null)
java.io.tmpdir = /var/folders/w5/mmnzpk0n369dntp4nszlc8h40000gn/T/ (null)
user.dir = /path/to/my-jetty-base (null)
user.language = en (null)
user.country = US (null)
Jetty Environment:
-----------------
jetty.version = 9.4.15.v20190215
jetty.tag.version = master
jetty.home = /path/to/jetty-home
jetty.base = /path/to/my-jetty-base
...(snip lots of output)...
Jetty Active XMLs:
------------------
${jetty.home}/etc/jetty-threadpool.xml
${jetty.home}/etc/jetty.xml
${jetty.home}/etc/jetty-webapp.xml
${jetty.home}/etc/jetty-plus.xml
${jetty.home}/etc/jetty-annotations.xml
${jetty.home}/etc/jetty-deploy.xml
${jetty.home}/etc/jetty-http.xml
${jetty.home}/etc/jetty-ssl.xml <-- THIS LINE
${jetty.home}/etc/jetty-ssl-context.xml
${jetty.home}/etc/jetty-https.xml
${jetty.home}/etc/jetty-jaas.xml
${jetty.home}/etc/jetty-rewrite.xml
${jetty.base}/etc/demo-rewrite-rules.xml
${jetty.base}/etc/test-realm.xml
一旦你验证了这个基本级别的配置,你就可以继续使用这些属性了。
接下来,当您向该安全连接器发出请求时,各种过滤器和 servlet 将可以访问许多可能对您有用的请求属性。
这些是 Servlet 规范定义的属性,SecureRequestCustomizer
添加到传入的 HttpServletRequest。
javax.servlet.request.X509Certificate
包含 java.security.cert.X509Certificate
个对象的数组。
javax.servlet.request.cipher_suite
将协商的密码套件作为 String
对象保存。
javax.servlet.request.key_size
将您的密钥大小保存为 Integer
对象。
javax.servlet.request.ssl_session_id
将您的 SSL 会话 ID 作为 String
对象保存。
这些是 SecureRequestCustomizer
添加到您传入的 HttpServletRequests 的 Jetty 自定义属性。
org.eclipse.jetty.servlet.request.ssl_session
持有此连接的活动 java.net.ssl.SSLSession
对象。
由于您在尝试使用该属性时看到了通用 Object[]
,也许您应该调试并查看这些对象的实际内容。
考虑到 Jetty 无法控制的某些东西可能已经替换了它们,或者在您尝试访问它们之前使 Jetty 无法以 Servlet 规范形式使用它们。
- 已知一些第 3 方安全库过去会更改这些属性。
- 或者你没有终止 Jetty 的 TLS/SSL 连接,例如 firewall/router/load 平衡器(haproxy、nginx、apache httpd 或各种硬件)(这意味着 Jetty 看不到证书).
- 您使用的不是普通的 ServerConnector(例如 UnixSocketConnector、LocalConnector 或自定义连接器)
- 或者您的 Java 实施中有第 3 方安全层。
Object certs[] = httpRequest.getAttribute("javax.servlet.request.X509Certificate");
for(Object cert: certs) {
System.out.printf("DEBUG: Cert[%s] = %s%n", cert.getClass().getName(), cert);
}
我在 Java
中将 Jersey
用作 REST
服务器,将 Jetty
用作 Web 服务器。我有 self signed
个证书。我想从收到的 HTTP 请求中获取客户端证书详细信息。如何获取HttpServletRequest
的信息?
一种方法:
X509Certificate certs[] = (X509Certificate[])httpRequest.getAttribute("javax.servlet.request.X509Certificate");
这样对吗?这导致异常,
Error [Ljava.lang.Object; cannot be cast to [Ljava.security.cert.X509Certificate
我应该添加任何额外的 JAR
吗?或者有什么办法可以获取客户端证书的详细信息?
我也遇到了,
httpRequest.getHeader("ssl_client_cert");
这两种方式似乎都不适合我。如何获取详情?
首先,确保处理 SSL/TLS 的 ServerConnector。 接下来,该 ServerConnector 应该有一个 SslConnectionFactory,其中配置了一个 HttpConfiguration 对象。 该 HttpConfiguration 对象应添加 SecureRequestCustomizer。
用嵌入式码头的说法,它看起来像这样...
// SSL Context Factory
SslContextFactory sslContextFactory = new SslContextFactory();
sslContextFactory.setKeyStorePath("/path/to/keystore");
sslContextFactory.setKeyStorePassword("password");
sslContextFactory.setKeyManagerPassword("secret");
sslContextFactory.setTrustStorePath("/path/to/keystore");
sslContextFactory.setTrustStorePassword("password");
// SSL HTTP Configuration
HttpConfiguration https_config = new HttpConfiguration(http_config);
https_config.addCustomizer(new SecureRequestCustomizer()); // <-- THIS LINE
// SSL Connector
ServerConnector sslConnector = new ServerConnector(server,
new SslConnectionFactory(sslContextFactory,HttpVersion.HTTP_1_1.asString()),
new HttpConnectionFactory(https_config));
sslConnector.setPort(8443);
server.addConnector(sslConnector);
如果您在独立 Jetty 上使用 ${jetty.home}
和 ${jetty.base}
拆分,那么您需要检查配置中是否存在 jetty-ssl.xml
...
$ cd /path/to/my-jetty-base
$ java -jar /path/to/jetty-home/start.jar --list-config
Java Environment:
-----------------
java.home = /Library/Java/JavaVirtualMachines/jdk1.8.0_202.jdk/Contents/Home/jre (null)
java.vm.vendor = Oracle Corporation (null)
java.vm.version = 25.202-b08 (null)
java.vm.name = Java HotSpot(TM) 64-Bit Server VM (null)
java.vm.info = mixed mode (null)
java.runtime.name = Java(TM) SE Runtime Environment (null)
java.runtime.version = 1.8.0_202-b08 (null)
java.io.tmpdir = /var/folders/w5/mmnzpk0n369dntp4nszlc8h40000gn/T/ (null)
user.dir = /path/to/my-jetty-base (null)
user.language = en (null)
user.country = US (null)
Jetty Environment:
-----------------
jetty.version = 9.4.15.v20190215
jetty.tag.version = master
jetty.home = /path/to/jetty-home
jetty.base = /path/to/my-jetty-base
...(snip lots of output)...
Jetty Active XMLs:
------------------
${jetty.home}/etc/jetty-threadpool.xml
${jetty.home}/etc/jetty.xml
${jetty.home}/etc/jetty-webapp.xml
${jetty.home}/etc/jetty-plus.xml
${jetty.home}/etc/jetty-annotations.xml
${jetty.home}/etc/jetty-deploy.xml
${jetty.home}/etc/jetty-http.xml
${jetty.home}/etc/jetty-ssl.xml <-- THIS LINE
${jetty.home}/etc/jetty-ssl-context.xml
${jetty.home}/etc/jetty-https.xml
${jetty.home}/etc/jetty-jaas.xml
${jetty.home}/etc/jetty-rewrite.xml
${jetty.base}/etc/demo-rewrite-rules.xml
${jetty.base}/etc/test-realm.xml
一旦你验证了这个基本级别的配置,你就可以继续使用这些属性了。
接下来,当您向该安全连接器发出请求时,各种过滤器和 servlet 将可以访问许多可能对您有用的请求属性。
这些是 Servlet 规范定义的属性,SecureRequestCustomizer
添加到传入的 HttpServletRequest。
javax.servlet.request.X509Certificate
包含java.security.cert.X509Certificate
个对象的数组。javax.servlet.request.cipher_suite
将协商的密码套件作为String
对象保存。javax.servlet.request.key_size
将您的密钥大小保存为Integer
对象。javax.servlet.request.ssl_session_id
将您的 SSL 会话 ID 作为String
对象保存。
这些是 SecureRequestCustomizer
添加到您传入的 HttpServletRequests 的 Jetty 自定义属性。
org.eclipse.jetty.servlet.request.ssl_session
持有此连接的活动java.net.ssl.SSLSession
对象。
由于您在尝试使用该属性时看到了通用 Object[]
,也许您应该调试并查看这些对象的实际内容。
考虑到 Jetty 无法控制的某些东西可能已经替换了它们,或者在您尝试访问它们之前使 Jetty 无法以 Servlet 规范形式使用它们。
- 已知一些第 3 方安全库过去会更改这些属性。
- 或者你没有终止 Jetty 的 TLS/SSL 连接,例如 firewall/router/load 平衡器(haproxy、nginx、apache httpd 或各种硬件)(这意味着 Jetty 看不到证书).
- 您使用的不是普通的 ServerConnector(例如 UnixSocketConnector、LocalConnector 或自定义连接器)
- 或者您的 Java 实施中有第 3 方安全层。
Object certs[] = httpRequest.getAttribute("javax.servlet.request.X509Certificate");
for(Object cert: certs) {
System.out.printf("DEBUG: Cert[%s] = %s%n", cert.getClass().getName(), cert);
}