Подтвердить что ты не робот

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

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

Это происходит из-за того, что сервер, предположительно, обновляется до TLS 1.2 и больше не принимает какой-либо более старый протокол (вызывает возврат "Connection Reset" ).

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

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

4b9b3361

Ответ 1

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

Образец пользовательского сокета factory находится здесь здесь, но вместо этого я сделал:

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

}

Ответ 2

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

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

Ответ 3

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

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

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

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

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

1) Если вы используете raw socket и 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