HttpClientでサポートされているTLSバージョンを変更するにはどうすればよいですか?
私がやっている:
SSLContext sslContext = SSLContext.getInstance("TLSv1.1");
sslContext.init(
keymanagers.toArray(new KeyManager[keymanagers.size()]),
null,
null);
SSLSocketFactory socketFactory = new SSLSocketFactory(sslContext, new String[]{"TLSv1.1"}, null, null);
Scheme scheme = new Scheme("https", 443, socketFactory);
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(scheme);
BasicClientConnectionManager cm = new BasicClientConnectionManager(schemeRegistry);
httpClient = new DefaultHttpClient(cm);
しかし、作成されたソケットを確認すると、サポートされているプロトコルはまだTLSv1.0、TLSv1.1、およびTLSv1.2であると表示されます。
実際には、この特定のHttpClientに対して、TLSv1.2の使用を停止するだけです。
解決策は次のとおりです。
SSLContext sslContext = SSLContexts.custom()
.useTLS()
.build();
SSLConnectionSocketFactory f = new SSLConnectionSocketFactory(
sslContext,
new String[]{"TLSv1", "TLSv1.1"},
null,
BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
httpClient = HttpClients.custom()
.setSSLSocketFactory(f)
.build();
ただし、これにはorg.Apache.httpcomponents.httpclient 4.3.xが必要です。
これは私がhttpClient 4.5で動作するようにした方法です(オリーブツリーのリクエストに従って):
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(
new AuthScope(AuthScope.ANY_Host, 443),
new UsernamePasswordCredentials(this.user, this.password));
SSLContext sslContext = SSLContexts.createDefault();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext,
new String[]{"TLSv1", "TLSv1.1"},
null,
new NoopHostnameVerifier());
CloseableHttpClient httpclient = HttpClients.custom()
.setDefaultCredentialsProvider(credsProvider)
.setSSLSocketFactory(sslsf)
.build();
return httpclient;
HttpClient-4.5、TLSv1.2を使用、次のようにコーディングする必要があります。
//Set the https use TLSv1.2
private static Registry<ConnectionSocketFactory> getRegistry() throws KeyManagementException, NoSuchAlgorithmException {
SSLContext sslContext = SSLContexts.custom().build();
SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext,
new String[]{"TLSv1.2"}, null, SSLConnectionSocketFactory.getDefaultHostnameVerifier());
return RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.register("https", sslConnectionSocketFactory)
.build();
}
public static void main(String... args) {
try {
//Set the https use TLSv1.2
PoolingHttpClientConnectionManager clientConnectionManager = new PoolingHttpClientConnectionManager(getRegistry());
clientConnectionManager.setMaxTotal(100);
clientConnectionManager.setDefaultMaxPerRoute(20);
HttpClient client = HttpClients.custom().setConnectionManager(clientConnectionManager).build();
//Then you can do : client.execute(HttpGet or HttpPost);
} catch (KeyManagementException | NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
TLSv1.2を使用するHttpClient-4.1の場合、コードは次のようになります。
SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
sslContext.init(null, null, new SecureRandom());
SSLSocketFactory sf = new SSLSocketFactory(sslContext);
Scheme httpsScheme = new Scheme("https", 443, sf);
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(httpsScheme);
ClientConnectionManager cm = new SingleClientConnManager(schemeRegistry);
HttpClient client = new DefaultHttpClient(cm);
// Use client to make the connection and get the results.
デフォルトのHttpClientBuilder
でカスタムHttpClientConnectionManager
とともにHttpClient 4.5.xでHttpClientBuilder
を使用します。
SSLConnectionSocketFactory sslConnectionSocketFactory =
new SSLConnectionSocketFactory(SSLContexts.createDefault(),
new String[] { "TLSv1.2" },
null,
SSLConnectionSocketFactory.getDefaultHostnameVerifier());
PoolingHttpClientConnectionManager poolingHttpClientConnectionManager =
new PoolingHttpClientConnectionManager(
RegistryBuilder.<ConnectionSocketFactory> create()
.register("http",
PlainConnectionSocketFactory.getSocketFactory())
.register("https",
sslConnectionSocketFactory)
.build());
// Customize the connection pool
CloseableHttpClient httpClient = HttpClientBuilder.create()
.setConnectionManager(poolingHttpClientConnectionManager)
.build()
カスタムHttpClientConnectionManager
なし:
SSLConnectionSocketFactory sslConnectionSocketFactory =
new SSLConnectionSocketFactory(SSLContexts.createDefault(),
new String[] { "TLSv1.2" },
null,
SSLConnectionSocketFactory.getDefaultHostnameVerifier());
CloseableHttpClient httpClient = HttpClientBuilder.create()
.setSSLSocketFactory(sslConnectionSocketFactory)
.build()
Httpclient 4.2を使用している場合、少し余分なコードを書く必要があります。 「TLS対応プロトコル」(具体的にはTLSv1.1
、特にTLSv1
もTLSv1.2
でもない)と 暗号スイート の両方をカスタマイズできるようにしたかった。
public class CustomizedSSLSocketFactory
extends SSLSocketFactory
{
private String[] _tlsProtocols;
private String[] _tlsCipherSuites;
public CustomizedSSLSocketFactory(SSLContext sslContext,
X509HostnameVerifier hostnameVerifier,
String[] tlsProtocols,
String[] cipherSuites)
{
super(sslContext, hostnameVerifier);
if(null != tlsProtocols)
_tlsProtocols = tlsProtocols;
if(null != cipherSuites)
_tlsCipherSuites = cipherSuites;
}
@Override
protected void prepareSocket(SSLSocket socket)
{
// Enforce client-specified protocols or cipher suites
if(null != _tlsProtocols)
socket.setEnabledProtocols(_tlsProtocols);
if(null != _tlsCipherSuites)
socket.setEnabledCipherSuites(_tlsCipherSuites);
}
}
次に:
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, getTrustManagers(), new SecureRandom());
// NOTE: not javax.net.SSLSocketFactory
SSLSocketFactory sf = new CustomizedSSLSocketFactory(sslContext,
null,
[TLS protocols],
[TLS cipher suites]);
Scheme httpsScheme = new Scheme("https", 443, sf);
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(httpsScheme);
ConnectionManager cm = new BasicClientConnectionManager(schemeRegistry);
HttpClient client = new DefaultHttpClient(cmgr);
...
これをわずかに少ないコードで実行できる場合もありますが、ほとんどの場合、上記の方法でオブジェクトを構築するのが理にかなっているカスタムコンポーネントからコピー/貼り付けを行いました。
コードに javax.net.ssl.SSLSocket クラス参照がある場合、 SSLSocket.setEnabledProtocols() を呼び出して、有効なTLSプロトコルを設定できます。
import javax.net.ssl.*;
import Java.net.*;
...
Socket socket = SSLSocketFactory.getDefault().createSocket();
...
if (socket instanceof SSLSocket) {
// "TLSv1.0" gives IllegalArgumentException in Java 8
String[] protos = {"TLSv1.2", "TLSv1.1"}
((SSLSocket)socket).setEnabledProtocols(protos);
}
-Dhttps.protocols = TLSv1.2 JVM引数を使用しても機能しませんでした。働いたのは次のコードです
RequestConfig.Builder requestBuilder = RequestConfig.custom();
//other configuration, for example
requestBuilder = requestBuilder.setConnectTimeout(1000);
SSLContext sslContext = SSLContextBuilder.create().useProtocol("TLSv1.2").build();
HttpClientBuilder builder = HttpClientBuilder.create();
builder.setDefaultRequestConfig(requestBuilder.build());
builder.setProxy(new HttpHost("your.proxy.com", 3333)); //if you have proxy
builder.setSSLContext(sslContext);
HttpClient client = builder.build();
次のJVM引数を使用して確認します
-Djavax.net.debug=all
サーバーで次のプロパティ-Dhttps.protocols = TLSv1.1、TLSv1.2を指定するだけで、クライアントからのすべてのhttps接続中に使用するTLSプロトコルバージョンを指定するJVMを構成できます。
これはコメントに隠されているだけなので、解決策として見つけるのは困難です:
あなたはcanJava -Dhttps.protocols=TLSv1,TLSv1.1
を使用できますが、 seSystemProperties() も使用する必要があります
client = HttpClientBuilder.create().useSystemProperties();
コードの一部の使用に対してのみこれを設定できるため、システムでこのセットアップを使用します。私たちの場合、まだいくつかのJava 7が実行されており、1つのAPIエンドポイントでTLSv1が許可されていないため、Java -Dhttps.protocols=TLSv1,TLSv1.1,TLSv1.2
を使用して現在のTLSバージョンを有効にします。 @jebeaudet、この方向を指し示してくれてありがとう。