Sta*_*ros 3 java ssl openjdk apache-httpclient-4.x
我们有一小组运行OpenJDK v1.7.0_111的Tomcat服务器.我们计划在今年夏天升级它们并进行迁移,但我们发现我们与之交互的客户端API在短期内需要TLSv1.2.我的最终愿望是找到一个配置更改以实现此目的.
托管在那里的应用程序以非常直接的方式创建它的SSL上下文:
SSLContext sslContext = SSLContexts.createDefault()
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext);
Run Code Online (Sandbox Code Playgroud)
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);
}
}
Run Code Online (Sandbox Code Playgroud)
在整个SSLConnectionSocketFactory课程中,似乎只是使用该SSLSocket.getEnabledProtocols()方法来确定哪些协议可供使用.请注意,this.supportedProtocols在我的情况下为null.
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()]));
}
}
Run Code Online (Sandbox Code Playgroud)
我遇到的问题是,在运行一些初步测试时,我无法让这些客户端连接到需要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();
}
}
Run Code Online (Sandbox Code Playgroud)
随着-Dhttps.protocols=TLSv1.2我已经尝试过-Djdk.tls.client.protocols=TLSv1.2和-Ddeployment.security.TLSv1.2=trueJVM参数没有任何运气.
有没有人想过如何在不升级到v8或更改应用程序以专门请求TLSv1.2实例的情况下在此配置中启用TLSv1.2?
jdk.tls.client.protocols 仅适用于您未使用的Java 8(可能是9).
https.protocols仅适用于HttpsURLConnectionhttpclient不使用的默认设置.
deployment.* 仅适用于您未使用的JNLP和applet(如果任何浏览器仍允许applet).
如果你使用HttpClientBuilder或HttpClients(你没有说过),你的Q的回答至少是4.5 ,分别是使用.useSystemProperties()或者.createSystem(); 这些确实使用相同的系统属性*URLConnection- 或者至少包括其中的许多属性https.protocols.您应该检查此集中包含的其他任何属性是否都配置为执行您不想要的操作.这确实需要更改应用程序,但不要将它们更改为专门请求... TLSv1.2'.
除此之外,您可以配置SSLConnectionSocketFactory指定允许的确切协议,如在@pvg链接的Q中,或SSLContexts.custom().useProtocol(String).build()指定上限 - 这对于您的情况就足够了,因为向需要的服务器提供范围"最多1.2" 1.2将选择1.2.