web-dev-qa-db-ja.com

Apache HttpClientでTLSバージョンを設定する方法

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の使用を停止するだけです。

35
Oliveira

解決策は次のとおりです。

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が必要です。

35
Oliveira

これは私が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;
14
douglaslps

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();
    }
}
8
sfxm

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.
5
user2122524

デフォルトの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()
5
jebeaudet

Httpclient 4.2を使用している場合、少し余分なコードを書く必要があります。 「TLS対応プロトコル」(具体的にはTLSv1.1、特にTLSv1TLSv1.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);
    ...

これをわずかに少ないコードで実行できる場合もありますが、ほとんどの場合、上記の方法でオブジェクトを構築するのが理にかなっているカスタムコンポーネントからコピー/貼り付けを行いました。

2

コードに 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);
}
2
IgorGanapolsky

-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
0
duvo

サーバーで次のプロパティ-Dhttps.protocols = TLSv1.1、TLSv1.2を指定するだけで、クライアントからのすべてのhttps接続中に使用するTLSプロトコルバージョンを指定するJVMを構成できます。

0
Sachin Kumar

これはコメントに隠されているだけなので、解決策として見つけるのは困難です:

あなたは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、この方向を指し示してくれてありがとう。

0
JonnyJD