web-dev-qa-db-ja.com

okHttpを使用してすべての証明書を信頼する

テスト目的で、プロキシが設定されている間、すべてを信頼するソケットファクトリをokHttpクライアントに追加しようとしています。これは何度も行われましたが、信頼できるソケットファクトリの私の実装には何かが欠けているようです:

class TrustEveryoneManager implements X509TrustManager {
    @Override
    public void checkClientTrusted(Java.security.cert.X509Certificate[] chain, String authType) throws CertificateException { }

    @Override
    public void checkServerTrusted(Java.security.cert.X509Certificate[] chain, String authType) throws CertificateException { }

    @Override
    public Java.security.cert.X509Certificate[] getAcceptedIssuers() {
        return null;
    }
}
OkHttpClient client = new OkHttpClient();

final InetAddress ipAddress = InetAddress.getByName("XX.XXX.XXX.XXX"); // some IP
client.setProxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(ipAddress, 8888)));

SSLContext sslContext = SSLContext.getInstance("TLS");
TrustManager[] trustManagers = new TrustManager[]{new TrustEveryoneManager()};
sslContext.init(null, trustManagers, null);
client.setSslSocketFactory(sslContext.getSocketFactory);

アプリからリクエストが送信されておらず、例外がログに記録されていないため、okHttp内でサイレントに失敗しているようです。さらに調査すると、ハンドシェイクが強制されているときにokHttpのConnection.upgradeToTls()に例外が飲み込まれているようです。私が与えられている例外は:javax.net.ssl.SSLException: SSL handshake terminated: ssl=0x74b522b0: SSL_ERROR_ZERO_RETURN occurred. You should never see this.

次のコードはSSLContextを生成します。これは、例外をスローしないSSLSocketFactoryを作成する際の魅力のように機能します。

protected SSLContext getTrustingSslContext() throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
    final SSLContextBuilder trustingSSLContextBuilder = SSLContexts.custom()
            .loadTrustMaterial(null, new TrustStrategy() {
                @Override
                public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                    return true; // Accepts any ssl cert whether valid or not.
                }
            });
    return trustingSSLContextBuilder.build();
}

問題は、アプリからすべてのApache HttpClient依存関係を完全に削除しようとしていることです。 SSLContextを生成するためのApache HttpClientを使用した基礎コードは十分に単純ですが、これに合わせてSSLContextを構成できないため、明らかに何かが欠けています。

Apache HttpClientを使用せずに私が望むことを行うSSLContext実装を作成できる人はいますか?

92
seato

誰かがここに落ちた場合に備えて、私のために働いた(唯一の)解決策は、説明されたようにOkHttpClientを作成することです here

コードは次のとおりです。

private static OkHttpClient getUnsafeOkHttpClient() {
  try {
    // Create a trust manager that does not validate certificate chains
    final TrustManager[] trustAllCerts = new TrustManager[] {
        new X509TrustManager() {
          @Override
          public void checkClientTrusted(Java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
          }

          @Override
          public void checkServerTrusted(Java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
          }

          @Override
          public Java.security.cert.X509Certificate[] getAcceptedIssuers() {
            return new Java.security.cert.X509Certificate[]{};
          }
        }
    };

    // Install the all-trusting trust manager
    final SSLContext sslContext = SSLContext.getInstance("SSL");
    sslContext.init(null, trustAllCerts, new Java.security.SecureRandom());
    // Create an ssl socket factory with our all-trusting manager
    final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();

    OkHttpClient.Builder builder = new OkHttpClient.Builder();
    builder.sslSocketFactory(sslSocketFactory, (X509TrustManager)trustAllCerts[0]);
    builder.hostnameVerifier(new HostnameVerifier() {
      @Override
      public boolean verify(String hostname, SSLSession session) {
        return true;
      }
    });

    OkHttpClient okHttpClient = builder.build();
    return okHttpClient;
  } catch (Exception e) {
    throw new RuntimeException(e);
  }
}
212
sonxurxo

次のメソッドは非推奨です

sslSocketFactory(SSLSocketFactory sslSocketFactory)

に更新することを検討してください

sslSocketFactory(SSLSocketFactory sslSocketFactory, X509TrustManager trustManager)
13
Jakub N

SSLSocketFactoryは、X509TrustManagerを公開しません。X509TrustManagerは、OkHttpがクリーンな証明書チェーンを構築するために必要なフィールドです。代わりに、このメソッドはリフレクションを使用してトラストマネージャーを抽出する必要があります。アプリケーションは、sslSocketFactory(SSLSocketFactory、X509TrustManager)を呼び出すことを選択する必要があります。これにより、このようなリフレクションが回避されます。

ソース: OkHttpドキュメント

OkHttpClient.Builder builder = new OkHttpClient.Builder();

builder.sslSocketFactory(sslContext.getSocketFactory(),
    new X509TrustManager() {
        @Override
        public void checkClientTrusted(Java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
        }

        @Override
        public void checkServerTrusted(Java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
        }

        @Override
        public Java.security.cert.X509Certificate[] getAcceptedIssuers() {
            return new Java.security.cert.X509Certificate[]{};
        }
    });
11

OkHttp 3.0を更新し、getAcceptedIssuers()関数はnullの代わりに空の配列を返す必要があります。

11
Ervin Zhang

誰かがそれを必要とするなら、これはKotlinのsonxurxoのソリューションです。

private fun getUnsafeOkHttpClient(): OkHttpClient {
    // Create a trust manager that does not validate certificate chains
    val trustAllCerts = arrayOf<TrustManager>(object : X509TrustManager {
        override fun checkClientTrusted(chain: Array<out X509Certificate>?, authType: String?) {
        }

        override fun checkServerTrusted(chain: Array<out X509Certificate>?, authType: String?) {
        }

        override fun getAcceptedIssuers() = arrayOf<X509Certificate>()
    })

    // Install the all-trusting trust manager
    val sslContext = SSLContext.getInstance("SSL")
    sslContext.init(null, trustAllCerts, Java.security.SecureRandom())
    // Create an ssl socket factory with our all-trusting manager
    val sslSocketFactory = sslContext.socketFactory

    return OkHttpClient.Builder()
        .sslSocketFactory(sslSocketFactory, trustAllCerts[0] as X509TrustManager)
        .hostnameVerifier { _, _ -> true }.build()
}

3
doodla

誰かがそれを必要とする場合、これはScalaソリューションです

def anUnsafeOkHttpClient(): OkHttpClient = {
val manager: TrustManager =
  new X509TrustManager() {
    override def checkClientTrusted(x509Certificates: Array[X509Certificate], s: String) = {}

    override def checkServerTrusted(x509Certificates: Array[X509Certificate], s: String) = {}

    override def getAcceptedIssuers = Seq.empty[X509Certificate].toArray
  }
val trustAllCertificates =  Seq(manager).toArray

val sslContext = SSLContext.getInstance("SSL")
sslContext.init(null, trustAllCertificates, new Java.security.SecureRandom())
val sslSocketFactory = sslContext.getSocketFactory()
val okBuilder = new OkHttpClient.Builder()
okBuilder.sslSocketFactory(sslSocketFactory, trustAllCertificates(0).asInstanceOf[X509TrustManager])
okBuilder.hostnameVerifier(new NoopHostnameVerifier)
okBuilder.build()

}

0
netta