HTTP客户端如何传递客户端证书?

问题描述 投票:0回答:2

我想在服务 A 和 B 之间使用相互 SSL 身份验证。我目前正在使用 Java 实现从服务 A 传递客户端证书。我正在使用 Apache DefaultHttpClient 来执行我的请求。我能够从内部凭证管理器检索服务 A 的客户端证书,并将其保留为字节数组。

DefaultHttpClient client = new DefaultHttpClient();
byte [] certificate = localCertManager.retrieveCert();

我在这方面的经验很少,非常感谢您的帮助!

我想也许它应该以某种方式通过 HTTP 客户端中的参数或者标头中的参数传递。

如何用HTTP客户端传递客户端证书?

apache ssl https ssl-certificate apache-commons-httpclient
2个回答
22
投票

客户端证书是在建立连接时在 TLS 握手期间发送的,并且无法在该连接内通过 HTTP 发送。

沟通是这样分层的:

  • HTTP(应用层协议)
  • 内部的 TLS(表示层协议)
  • TCP(传输层协议)
  • IP(网络层协议)
您需要在 TLS 握手期间发送客户端证书,然后才能影响任何 HTTP(方法、标头、URL、请求正文)。服务器将不接受稍后发送的客户端证书。

我建议从

DefaultHttpClient (已弃用)切换到 CloseableHttpClient,这样可以更干净地使用 try-with-resources。

Apache HttpClient 4.5 使相互 TLS 相当方便。该答案已使用 Apache HttpClient 4.5.3 进行了测试。

基本的起点是使用

loadKeyMaterial 将客户端证书及其密钥(客户端密钥对)加载到 SSLContext:

SSLContext sslContext = SSLContexts.custom().loadKeyMaterial( MutualHttpsMain.class.getResource(TEST_CLIENT_KEYSTORE_RESOURCE), storePassword, keyPassword, (aliases, socket) -> aliases.keySet().iterator().next() ).build();
最后用该套接字工厂构建一个 HTTP 客户端:

CloseableHttpClient httpclient = HttpClients .custom().setSSLContext(sslContext).build();
使用该客户端,您的所有请求都可以通过隐含的相互 TLS 身份验证来执行:

CloseableHttpResponse closeableHttpResponse = httpclient.execute( new HttpGet(URI.create("https://mutual-tls.example.com/")));
这是使用 Apache HttpClient 的双向 TLS 的完整可运行示例:

import org.apache.http.HttpEntity; import org.apache.http.StatusLine; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.ssl.SSLContexts; import javax.net.ssl.SSLContext; import java.io.Console; import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.nio.ByteBuffer; import java.nio.channels.Channels; import java.nio.channels.ReadableByteChannel; import java.nio.channels.WritableByteChannel; import java.security.GeneralSecurityException; public class MutualHttpsMain { private static final String TEST_URL = "https://mutual-tls.example.com/"; private static final String TEST_CLIENT_KEYSTORE_RESOURCE = "/mutual-tls-keystore.p12"; public static void main(String[] args) throws GeneralSecurityException, IOException { Console console = System.console(); char[] storePassword = console.readPassword("Key+Keystore password: "); char[] keyPassword = storePassword; SSLContext sslContext = SSLContexts.custom().loadKeyMaterial( MutualHttpsMain.class.getResource(TEST_CLIENT_KEYSTORE_RESOURCE), storePassword, keyPassword, (aliases, socket) -> aliases.keySet().iterator().next() ).build(); try (CloseableHttpClient httpclient = HttpClients .custom().setSSLContext(sslContext).build(); CloseableHttpResponse closeableHttpResponse = httpclient.execute( new HttpGet(URI.create(TEST_URL)))) { console.writer().println(closeableHttpResponse.getStatusLine()); HttpEntity entity = closeableHttpResponse.getEntity(); try (InputStream content = entity.getContent(); ReadableByteChannel src = Channels.newChannel(content); WritableByteChannel dest = Channels.newChannel(System.out)) { ByteBuffer buffer = ByteBuffer.allocateDirect(16 * 1024); while (src.read(buffer) != -1) { buffer.flip(); dest.write(buffer); buffer.compact(); } buffer.flip(); while (buffer.hasRemaining()) dest.write(buffer); } } } }
通常最好使用 Gradle 或 Maven 来运行这样的东西,但为了尽可能减少 Yak shave,我提供了用于构建和运行它的基线 JDK 指令。

从以下页面下载 JAR:

  • Apache HttpClient 4.5.3
  • Apache Commons 编解码器 1.10
  • Apache Commons 日志记录 1.2
  • Apache HttpCore 4.4.8
将上面的完整示例保存为

MutualHttpsMain.java

将您的 PKCS#12 复制到同一目录中的

mutual-tls-keystore.p12

按如下方式编译(在 macOS/Linux/*nix-likes 上):

javac MutualHttpsMain.java -cp httpclient-4.5.3.jar:httpcore-4.4.8.jar
或者在 Windows 上:

javac MutualHttpsMain.java -cp httpclient-4.5.3.jar;httpcore-4.4.8.jar
按如下方式运行(在 macOS/Linux/*nix-likes 上):

java -cp httpclient-4.5.3.jar:commons-codec-1.10.jar:commons-logging-1.2.jar:httpcore-4.4.8.jar:. MutualHttpsMain
运行如下(在 Windows 上):

java -cp httpclient-4.5.3.jar;commons-codec-1.10.jar;commons-logging-1.2.jar;httpcore-4.4.8.jar;. MutualHttpsMain
    

8
投票
删除已接受的部分最佳答案的正文,请参阅

https://stackoverflow.com/a/46821977/98959

© www.soinside.com 2019 - 2024. All rights reserved.