我们有一小组运行OpenJDK v1.7.0_111的Tomcat服务器。我们计划在今年夏天升级它们并进行迁移,但我们发现我们与之交互的客户端API在短期内需要TLSv1.2。我的最终愿望是找到配置更改以实现此目的。
在那里托管的应用程序以非常直接的方式创建了它的SSL上下文:
SSLContext sslContext = SSLContexts.createDefault()
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext);
SSLContexts
来自Apache的httpclient库(版本4.4.1),并且非常直接地介绍了它如何创建SSL上下文:
public static SSLContext createDefault() throws SSLInitializationException {
try {
SSLContext ex = SSLContext.getInstance("TLS");
ex.init((KeyManager[])null, (TrustManager[])null, (SecureRandom)null);
return ex;
} catch (NoSuchAlgorithmException var1) {
throw new SSLInitializationException(var1.getMessage(), var1);
} catch (KeyManagementException var2) {
throw new SSLInitializationException(var2.getMessage(), var2);
}
}
通过SSLConnectionSocketFactory
类挖掘,似乎只是使用SSLSocket.getEnabledProtocols()
方法来确定哪些协议可供使用。请注意,this.supportedProtocols
在我的情况下为空。
public Socket createLayeredSocket(Socket socket, String target, int port, HttpContext context) throws IOException {
SSLSocket sslsock = (SSLSocket)this.socketfactory.createSocket(socket, target, port, true);
if(this.supportedProtocols != null) {
sslsock.setEnabledProtocols(this.supportedProtocols);
} else {
String[] allProtocols = sslsock.getEnabledProtocols();
ArrayList enabledProtocols = new ArrayList(allProtocols.length);
String[] arr$ = allProtocols;
int len$ = allProtocols.length;
for(int i$ = 0; i$ < len$; ++i$) {
String protocol = arr$[i$];
if(!protocol.startsWith("SSL")) {
enabledProtocols.add(protocol);
}
}
if(!enabledProtocols.isEmpty()) {
sslsock.setEnabledProtocols((String[])enabledProtocols.toArray(new String[enabledProtocols.size()]));
}
}
我遇到的问题是,在进行一些初步测试时,我无法让这些客户端连接到需要TLSv1.2的API。
在下面的示例中,我可以通过包含URLConnection
参数来完成-Dhttps.protocols=TLSv1.2
代码,但我无法连接Apache连接。
public static void main(String[] args) throws Exception{
String testURL = "https://testapi.com";
SSLContext sslcontext = SSLContext.getInstance("TLS");
sslcontext.init(null, null, null);
try {
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslcontext);
CloseableHttpClient client = HttpClients.custom().setSSLSocketFactory(socketFactory).build();
HttpGet httpget = new HttpGet(testURL);
CloseableHttpResponse response = client.execute(httpget);
System.out.println("Response Code (Apache): " + response.getStatusLine().getStatusCode());
}
catch (Exception e){
System.err.println("Apache HTTP Client Failed");
e.printStackTrace();
}
try {
HttpsURLConnection urlConnection = (HttpsURLConnection) new URL(testURL).openConnection();
urlConnection.setSSLSocketFactory(sslcontext.getSocketFactory());
urlConnection.connect();
System.out.println("Response Code (URLConnection): " + urlConnection.getResponseCode());
}
catch (Exception e){
System.err.println("HttpsURLConnection Failed");
e.printStackTrace();
}
}
与-Dhttps.protocols=TLSv1.2
一起,我尝试了-Djdk.tls.client.protocols=TLSv1.2
和-Ddeployment.security.TLSv1.2=true
JVM参数而没有任何运气。
有没有人想过如何在不升级到v8或更改应用程序以专门请求TLSv1.2实例的情况下在此配置中启用TLSv1.2?
答案 0 :(得分:6)
jdk.tls.client.protocols
仅适用于您未使用的Java 8(可能是9)。
https.protocols
仅在HttpsURLConnection
中默认使用,httpclient不使用。
deployment.*
仅适用于您未使用的JNLP和applet(如果任何浏览器仍允许applet)。
如上所述对你的问题的答案,至少4.5,假设你使用HttpClientBuilder
或HttpClients
(你没有说),就是使用{分别为{1}}或.useSystemProperties()
;这些 do 使用与.createSystem()
相同的系统属性 - 或者至少包括*URLConnection
中的许多属性。您应该检查此集中包含的其他任何属性是否都配置为执行您不想要的操作。这个确实需要更改应用,但不能将它们更改为具体请求... TLSv1.2'。
除此之外,您可以配置https.protocols
以指定the Q linked by @pvg中允许的确切协议,或SSLConnectionSocketFactory
以指定上限 - 这足以满足您的需求,因为提供对于需要1.2的服务器,“高达1.2”的范围将选择1.2。