Как заставить Commons HTTPClient 3.1 использовать TLS 1.2 только для HTTPS?

Я хочу силу Apache Commons HTTP-клиентом (вариант 3.1), чтобы использовать TLS 1.2 как только протокол для HTTPS.

это связано с тем, что сервер предположительно обновляется до TLS 1.2 и больше не принимает старый протокол (что приводит к возврату "сброса соединения").

для дальнейшего контекста, вероятно, неуместного, HTTP-клиент используется вместе с 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);

большое спасибо за помощь!

3 ответов


жаль, что никто не ответил; я смог это сделать, сначала вы пишете 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));
   }

}

вам нужна ссылка на сокет в вашем коде. Затем вы можете установить включенные протоколы на нем следующим образом:

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

Это зависит от того, как вы пишете своих клиентов и какие версии JRE вы используете:

Если вы используете JRE8 (если вы не заменили SunJSSE по умолчанию, который поставляется с JRE8), существует системное свойство "jdk.tls.клиент.протоколы." По умолчанию все, что вы здесь упомянули, будет использоваться для всех клиентских коммуникаций.

Если вы используете объект HttpsURLConnection для подключения клиента, u может использовать системное свойство " https.протоколы." Это будет работать для всех версии версии, а не только JRE8.

Если вы ничего не указываете, для клиентов TLS в JRE8, TLSv1, v1.1 и v1.2 включены, поэтому он будет работать с сервером, который поддерживает любую из этих версий. Однако в JRE7 по умолчанию включен только TLSv1.

в вашем коде u всегда может переопределить значение по умолчанию или то, что u проходит через системные свойства. Что в коде примут более высокий приоритет. Для переопределения в коде...

1) Если вы используете raw сокет и SSLEngine, u может установить протокол и шифры в SSLEngine (sslEngine.setEnabledProtocols(..)

2) Если вы используете SSLSocket, u может установить протокол и шифры в SSLSocket (sslSocket.setEnabledProtocols(..)

вы также можете получить SSLContext с включенным необходимым протоколом и использовать его для любых используемых вами компонентов SSL. Возвращаетsslcontextэкземпляр.getInstance ("TLSvx.икс.)" Обратите внимание, что по умолчанию он вернет контекст со всеми протоколами, меньшими, чем TLSvx.X включено. Если вы настроили " jdk.tls.клиент.протоколы", это вернет контекст с включенными протоколами.

было бы не очень хорошей идеей жестко закодировать протоколы в коде. Довольно часто мы сталкиваемся с определенными клиентами, которые хотят конкретную версию либо потому, что они используют старые серверы, либо некоторые серьезные уязвимости встречаются в некоторых версиях 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