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