Как заставить 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);

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


person abdelrahman-sinno    schedule 15.09.2015    source источник
comment
Поскольку вы используете это старое и неподдерживаемое программное обеспечение, я предполагаю, что вы также используете старую версию Java. Вы уверены, что ваша Java вообще может говорить на Java 1.2 (т.е. какую версию Java вы используете?)   -  person Steffen Ullrich    schedule 15.09.2015
comment
Нет, я использую Java 7, и код не слишком старый, до сих пор он работает довольно хорошо.   -  person abdelrahman-sinno    schedule 15.09.2015


Ответы (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));
   }

}
person abdelrahman-sinno    schedule 16.09.2015
comment
Отличается ли SecureProtocolSocketFactory от SSLSocketFactory? - person IgorGanapolsky; 20.04.2016
comment
SecureProtocolSocketFactory — это интерфейс в Apache HTTPClient, полезный для реализации собственной фабрики сокетов; Я полагаю, что Java SSLSocketFactory будет менее полезным в этом случае. - person abdelrahman-sinno; 06.05.2016
comment
@united-expression У меня такое же требование, за исключением того, что я использую HTTP-клиент (версия 4.1). Ваш код полезен, хотя мне до сих пор не ясно, где вы связываете httpClient с этим зарегистрированным протоколом? - person LoveForDroid; 13.06.2016
comment
@united-expression, зачем в этом случае нужен отдельный класс и для чего нужен RegisterProtocol? Как будут вызываться методы CustomHttpsSocketFactory? - person Nimble Fungus; 16.09.2016
comment
Он показывает, что setEnabledProtocols(String[]); не определено для типа javax.net.ssl.SSLSocket. - person Vivek Mangal; 16.02.2018

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

if (socket != null && (socket instanceof SSLSocket)) {
    ((SSLSocket)socket).setEnabledProtocols(new String[] {"TLSv1.2"});
}
person IgorGanapolsky    schedule 21.04.2016
comment
Я не понимаю, как использовать это в моей реализации HttpClient (3.1). Где инициализируется объект сокета? Я также хочу убедиться, что протоколы, которые я установил, используются только моим HttpClient, но никакие другие классы/реализации, которые могут делать HTTP-запросы в другом месте. Использование Java 8 и в настоящее время невозможно выполнить обновление до других версий HttpClient. - person spinyBabbler; 09.11.2018
comment
@ChiefNish Это сокет Java: docs.oracle .com/javase/7/docs/api/javax/net/ssl/SSLSocket.html - person IgorGanapolsky; 10.11.2018
comment
Означает ли это, что HttpClient, руководство которого говорит, что HttpClient обеспечивает полную поддержку HTTP через протоколы Secure Sockets Layer (SSL) или IETF Transport Layer Security (TLS), используя Java Secure Socket Extension (JSSE). , означает, что по умолчанию сокеты, предоставляемые Java 8, включены? Итак, поддержка до TLSv1.2? Я намерен выяснить, какой протокол используется по умолчанию, а затем убедиться, что поддерживается как минимум SSL 3.0 и более поздние версии. Оказалось, что узнать сложнее, чем ожидалось, возможно, я задаю неправильные вопросы. Благодарю вас! - person spinyBabbler; 10.11.2018

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

Если вы используете JRE8 (если вы не заменили SunJSSE по умолчанию, поставляемый с JRE8), существует системное свойство "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

person Rajesh Jose    schedule 12.08.2016