如何强制Commons HTTPClient 3.1仅对HTTPS使用TLS 1.2?

我希望强制Apache Commons HTTP-Client3.1版)使用TLS 1.2作为HTTPS的唯一协议。

这是因为服务器应该升级到TLS 1.2并且不再接受任何旧协议(导致返回“连接重置”)。

对于进一步的上下文,可能不相关,HTTP-Client与Axis2一起用于创建SOAP; 用于设置HttpClient的一些代码如下:

MultiThreadedHttpConnectionManager connMgr = new MultiThreadedHttpConnectionManager(); this.httpClient = new HttpClient(connMgr); // initialize HttpClient parameters HttpClientParams hcParams = this.httpClient.getParams(); // Maximum time to wait to receive connection from pool hcParams.setConnectionManagerTimeout(this.maxWait); hcParams.setSoTimeout(this.timeout); hcParams.setParameter(HttpMethodParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler(this.retryCount, false)); // Initialize global Connection manager parameters HttpConnectionManagerParams cmParams = connMgr.getParams(); cmParams.setDefaultMaxConnectionsPerHost(this.maxActive); cmParams.setStaleCheckingEnabled(this.checkStaleConnections); cmParams.setConnectionTimeout(this.timeout); 

非常感谢您的帮助!

太糟糕没有人回答; 我能够做到这一点,首先你写一个CustomHttpSocketFactory ,然后你做:

 String scheme = "https"; Protocol baseHttps = Protocol.getProtocol(scheme); int defaultPort = baseHttps.getDefaultPort(); ProtocolSocketFactory baseFactory = baseHttps.getSocketFactory(); ProtocolSocketFactory customFactory = new CustomHttpsSocketFactory(baseFactory); Protocol customHttps = new Protocol(scheme, customFactory, defaultPort); Protocol.registerProtocol(scheme, customHttps); 

这里有一个示例自定义套接字工厂代码,但我做了:

 public class CustomHttpsSocketFactory implements SecureProtocolSocketFactory { private final SecureProtocolSocketFactory base; public CustomHttpsSocketFactory(ProtocolSocketFactory base) { if(base == null || !(base instanceof SecureProtocolSocketFactory)) throw new IllegalArgumentException(); this.base = (SecureProtocolSocketFactory) base; } private Socket acceptOnlyTLS12(Socket socket) { if(!(socket instanceof SSLSocket)) return socket; SSLSocket sslSocket = (SSLSocket) socket; sslSocket.setEnabledProtocols(new String[]{"TLSv1.2" }); return sslSocket; } @Override public Socket createSocket(String host, int port) throws IOException { return acceptOnlyTLS12(base.createSocket(host, port)); } @Override public Socket createSocket(String host, int port, InetAddress localAddress, int localPort) throws IOException { return acceptOnlyTLS12(base.createSocket(host, port, localAddress, localPort)); } @Override public Socket createSocket(String host, int port, InetAddress localAddress, int localPort, HttpConnectionParams params) throws IOException { return acceptOnlyTLS12(base.createSocket(host, port, localAddress, localPort, params)); } @Override public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException { return acceptOnlyTLS12(base.createSocket(socket, host, port, autoClose)); } } 

您的代码中需要一个Socket引用。 然后你可以像这样设置启用的协议:

 if (socket != null && (socket instanceof SSLSocket)) { ((SSLSocket)socket).setEnabledProtocols(new String[] {"TLSv1.2"}); } 

这取决于您编写客户端的方式以及您使用的JRE版本:

如果您使用的是JRE8(除非您已替换JRE8附带的默认SunJSSE),则系统属性为“jdk.tls.client.protocols”。 默认情况下,此处提及的任何内容都将用于所有客户端通信。

如果您使用HttpsURLConnection对象进行客户端连接,则可以使用系统属性“https.protocols”。 这适用于所有JRE版本,而不仅仅是JRE8。

如果您没有指定任何内容,对于TLS客户端,在JRE8中,TLSv1,v1.1和v1.2已启用,因此它将与支持任何一个版本的服务器一起使用。 但是,在JRE7中,默认情况下单独启用TLSv1。

在您的代码中,您可以始终覆盖默认值或您通过系统属性的内容。 您在代码中设置的内容将具有更高的优先级。 要覆盖代码……

1)如果你使用原始套接字和SSLEngine,你可以在SSLEngine中设置协议和密码(sslEngine.setEnabledProtocols(..)

2)如果您正在使用SSLSocket,您可以在SSLSocket中设置协议和密码(sslSocket.setEnabledProtocols(..)

您还可以获得启用了所需协议的SSLContext,并将其用于您使用的任何SSL组件。 SSLContext.getInstance( “TLSvx.x”)。 请注意,默认情况下,它将返回一个上下文,其中所有协议都比TLSvx.x启用的更少。 如果您已配置“jdk.tls.client.protocols”,则将返回启用了这些协议的上下文。

在代码中对协议进行硬编码不是一个好主意。 通常,我们会遇到某些客户需要特定版本,因为他们使用旧服务器或某些TLS版本中遇到一些严重漏洞。 通过系统属性设置它,或者即使您在sslsocket或sslengine中显式设置,也可以从某个conf文件中读取它。

另请参阅:

https://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html

http://docs.oracle.com/javase/8/docs/technotes/guides/security/SunProviders.html