How to force Commons HTTPClient 3.1 to use TLS 1.2 only for HTTPS?

前端 未结 3 1069
独厮守ぢ
独厮守ぢ 2020-12-03 01:38

I wish to force Apache Commons HTTP-Client (version 3.1) to use TLS 1.2 as the only pro

相关标签:
3条回答
  • 2020-12-03 01:50

    Too bad nobody answered; I was able to do it, first you write a CustomHttpSocketFactory, then you do:

    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); 
    

    A sample custom socket factory code is found here, but instead I did:

    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));
       }
    
    }
    
    0 讨论(0)
  • 2020-12-03 01:53

    You need a Socket reference in your code. Then you can set enabled protocols on it like this:

    if (socket != null && (socket instanceof SSLSocket)) {
        ((SSLSocket)socket).setEnabledProtocols(new String[] {"TLSv1.2"});
    }
    
    0 讨论(0)
  • 2020-12-03 01:56

    It depends on how you are writing your clients and what JRE versions you are using:

    If you are using JRE8 (unless you have replaced the default SunJSSE that comes with JRE8), there is a system property "jdk.tls.client.protocols". By default, whatever you mention here will be used for all client communication.

    If you are using HttpsURLConnection object for client connection, u can use the system property "https.protocols". This will work for all JRE versions, not just JRE8.

    If you don't specify anything, for TLS clients, in JRE8, TLSv1, v1.1 and v1.2 are enabled, so it will work with a server what supports any one of this versions. However in JRE7 by default TLSv1 alone is enabled.

    In your code u can always override the default or what u pass through the system properties. What u set in the code will take higher precedence. To override in the code...

    1) If you are using raw socket and SSLEngine, u can set the protocol and ciphers in the SSLEngine (sslEngine.setEnabledProtocols(..)

    2) If you are using SSLSocket, u can set the protocol and ciphers in the SSLSocket (sslSocket.setEnabledProtocols(..)

    You can also get an SSLContext with the required protocol enabled and use that for whatever SSL components you use. SSLContext.getInstance("TLSvx.x"). Note that by default it will return a context with all the protocols lesser that TLSvx.x enabled. If u have configured "jdk.tls.client.protocols", this will return a context with those protocols enabled.

    It would not be a good idea to hard coded the protocols in the code. Quite often, we will encounter certain customers want specific version either because they use old servers or some serious vulnerabilities are encountered in some TLS versions. Either set it through the system properties or even if you are explicitly setting in sslsocket or sslengine, read that from some conf file.

    Also refer:

    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

    0 讨论(0)
提交回复
热议问题