okHttpですべての証明書を信頼する


111

テストの目的で、プロキシが設定されている間すべてを信頼するソケットファクトリを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内で静かに失敗しているようです。さらに調査したConnection.upgradeToTls()ところ、ハンドシェイクが強制されているときにokHttpで例外が飲み込まれているようです。私が与えられている例外は: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依存関係を完全に削除しようとしていることです。Apache HttpClientを使用して基になるコードを生成するのSSLContextは簡単なようですが、SSLContextこれに一致するように構成できないため、明らかに何かが欠けています。

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


2
「テスト目的で、すべてを信頼するソケットファクトリをokHttpクライアントに追加しようとしています」-そもそも、これが良いアイデアだと思われる理由は何ですか?
CommonsWare 2014

1
完全に信頼できるネットワークでのみ呼び出されます。
seato 2014

これにより、java.net.SocketTimeoutException: Read timed out
IgorGanapolsky 2015年

回答:


249

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

これがコードです:

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);
  }
}

15
なぜSSLありませんかTLS
IgorGanapolsky

1
どうもありがとうございました!改造に関するドキュメント(okhttpを使用)が不足しています。この種のコードサンプルを使用すると、何度も何度も時間を節約できます。
Warpzit 2016年

8
このアプローチは、現在のバージョンのOkHttpでは機能しないことに注意してください。3.1.1では完全に壊れているようです。3.1.2以降でX509TrustManager.getAcceptedIssuers()は、ではなく空の配列を返す必要がありnullます。詳細については、このコミットを参照してください(下にスクロールして、RealTrustRootIndex.javaの下のメモを参照してください)。
jbxbergdev 2016

12
私はこれを試しましたが、それでもHandshake failed例外が発生します。助言がありますか?
エステバン


13

次のメソッドは廃止されました

sslSocketFactory(SSLSocketFactory sslSocketFactory)

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

sslSocketFactory(SSLSocketFactory sslSocketFactory, X509TrustManager trustManager)

13

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


2
@Override public X509Certificate [] getAcceptedIssuers(){return new X509Certificate [] {}; // StackOverflow}
Ervin Zhang

11

SSLSocketFactoryは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[]{};
        }
    });

これは自己署名証明書には機能しません。原因401権限エラーを。
IgorGanapolsky

5
どこsslContextから来たのですか?
Anonsage

3
どのように初期化しsslContextますか?
kiltek

9

誰かがそれを必要とする場合、これは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()
}

7

Kotlinの拡張機能を作りました。それを好きな場所に貼り付け、作成中にインポートしOkHttpClientます。

fun OkHttpClient.Builder.ignoreAllSSLErrors(): OkHttpClient.Builder {
    val naiveTrustManager = object : X509TrustManager {
        override fun getAcceptedIssuers(): Array<X509Certificate> = arrayOf()
        override fun checkClientTrusted(certs: Array<X509Certificate>, authType: String) = Unit
        override fun checkServerTrusted(certs: Array<X509Certificate>, authType: String) = Unit
    }

    val insecureSocketFactory = SSLContext.getInstance("TLSv1.2").apply {
        val trustAllCerts = arrayOf<TrustManager>(naiveTrustManager)
        init(null, trustAllCerts, SecureRandom())
    }.socketFactory

    sslSocketFactory(insecureSocketFactory, naiveTrustManager)
    hostnameVerifier(HostnameVerifier { _, _ -> true })
    return this
}

次のように使用します。

val okHttpClient = OkHttpClient.Builder().apply {
    // ...
    if (BuildConfig.DEBUG) //if it is a debug build ignore ssl errors
        ignoreAllSSLErrors()
    //...
}.build()

あなたが実際にこのようにそれを使用することができます:すべての後にOkHttpClient.Builder().ignoreAllSSLErrors().connectTimeout(api.timeout、TimeUnit.SECONDS).writeTimeout(api.timeout、TimeUnit.SECONDS)など、それはBuilderパターンだ
エマニュエルモエクリン

1

誰かがそれを必要とする場合、これは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()

}


-12

コードで証明書の検証をオーバーライドしないでください。テストを行う必要がある場合は、内部/テストCAを使用して、CAルート証明書をデバイスまたはエミュレーターにインストールします。CAの設定方法がわからない場合は、BurpSuiteまたはCharles Proxyを使用できます。


37
ああ、来る。会社で働いていて、VPN経由でHTTPSサーバーに接続するように強制されている場合はどうでしょう。テストでそれをどのようにシミュレートしますか?
IgorGanapolsky

5
これは最も純粋な豚の洗浄です。これはテストビルドでのみコンパイルするため、危険はありません。
Adam
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.