1. 简介
Apache HttpClient 是一个轻量、低级别的客户端 HTTP 库,用于与 HTTP 服务器进行通信。本文将介绍在使用 HttpClient 时如何配置所支持的传输层安全(TLS)版本。
我们将从 TLS 版本协商机制讲起,然后重点介绍 三种不同的方式来配置 HttpClient 所支持的 TLS 版本。在第 3 节中,我们还会说明 Apache HttpClient 4 在静态设置 TLS 配置方面的一些差异。
2. Apache HttpClient 5
2.1 TLS 版本协商机制
TLS 是一种互联网协议,用于在两个通信方之间建立安全、可信的连接。它封装了应用层协议(如 HTTP)。自 1999 年首次发布以来,TLS 协议已经经历了多次修订。因此,客户端和服务器在建立连接前,必须先协商好使用哪个版本的 TLS 协议。
TLS 版本协商过程如下:
- 客户端发送其支持的 TLS 版本列表;
- 服务器从中选择一个版本,并在响应中告知客户端;
- 双方使用选定的版本继续建立连接。
正确配置客户端支持的 TLS 版本非常重要,可以有效防范 降级攻击。⚠️ 注意:若要使用最新的 TLS 1.3,需要 Java 11 或更高版本。
2.2 静态配置 TLS 版本
2.2.1 使用 HttpClientConnectionManager
首先,我们创建一个自定义 TLS 配置的连接管理器,然后将其设置给通过 HttpClients.custom()
构建的 ClosableHttpClient
实例:
final HttpClientConnectionManager cm = PoolingHttpClientConnectionManagerBuilder.create()
.setDefaultTlsConfig(TlsConfig.custom()
.setHandshakeTimeout(Timeout.ofSeconds(30))
.setSupportedProtocols(TLS.V_1_2, TLS.V_1_3)
.build())
.build();
return HttpClients.custom().setConnectionManager(cm).build();
✅ 返回的 HttpClient
对象现在只会支持 TLS 1.2 和 TLS 1.3 的通信。
2.2.2 使用 Java 运行时参数
另一种方式是通过 Java 的 https.protocols
系统属性来配置支持的 TLS 版本,避免硬编码在代码中。我们可以让 HttpClient 使用系统属性来配置连接:
CloseableHttpClient httpClient = HttpClients.createSystem();
如果需要更多自定义配置,也可以使用构建器方式:
CloseableHttpClient httpClient = HttpClients.custom().useSystemProperties().build();
这两种方式都会让 HttpClient 在连接时读取系统属性。例如,我们可以通过以下命令启动应用:
$ java -Dhttps.protocols=TLSv1.1,TLSv1.2,TLSv1.3 -jar webClient.jar
2.3 动态配置 TLS 版本
我们也可以根据连接的主机名或端口动态设置 TLS 版本。做法是继承 SSLConnectionSocketFactory
并重写 prepareSocket
方法。该方法在建立连接前被调用,从而允许我们按连接动态选择 TLS 版本。
示例:仅对特定子域名启用旧版 TLS:
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(SSLContexts.createDefault()) {
@Override
protected void prepareSocket(SSLSocket socket) {
String hostname = socket.getInetAddress().getHostName();
if (hostname.endsWith("internal.system.com")) {
socket.setEnabledProtocols(new String[] { "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3" });
} else {
socket.setEnabledProtocols(new String[] {"TLSv1.3"});
}
}
};
CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
✅ 上述代码中,prepareSocket
方法会根据目标主机名决定启用哪些 TLS 协议。除了匹配 *.internal.system.com
的主机外,其他请求都强制使用 TLS 1.3。
3. Apache HttpClient 4
3.1 静态配置 TLS 版本
3.1.1 使用 SSLConnectionSocketFactory
在 HttpClient 4 中,我们可以使用 HttpClients.custom()
返回的 HttpClientBuilder
来自定义配置,并传入一个自定义的 SSLConnectionSocketFactory
实例:
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
SSLContexts.createDefault(),
new String[] { "TLSv1.2", "TLSv1.3" },
null,
SSLConnectionSocketFactory.getDefaultHostnameVerifier());
CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
✅ 此方式下,HttpClient 只支持 TLS 1.2 和 TLS 1.3。⚠️ 注意:在 HttpClient 4.3 之前的版本中,该类名为 SSLSocketFactory
。
4. 总结
本文介绍了在使用 Apache HttpClient 时配置 TLS 版本的三种方式,包括:
- 全局静态配置(如通过连接管理器或系统属性)
- 动态配置(基于连接目标的自定义逻辑)
通过这些方法,我们可以灵活控制客户端所支持的 TLS 版本,提升通信安全性。✅ 推荐在生产环境中强制使用 TLS 1.2 或更高版本,避免兼容过旧协议带来的安全风险。