テスト目的で、プロキシが設定されている間、すべてを信頼するソケットファクトリを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実装を作成できる人はいますか?
誰かがここに落ちた場合に備えて、私のために働いた(唯一の)解決策は、説明されたように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);
}
}
次のメソッドは非推奨です
sslSocketFactory(SSLSocketFactory sslSocketFactory)
に更新することを検討してください
sslSocketFactory(SSLSocketFactory sslSocketFactory, X509TrustManager trustManager)
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[]{};
}
});
OkHttp 3.0を更新し、getAcceptedIssuers()
関数はnull
の代わりに空の配列を返す必要があります。
誰かがそれを必要とするなら、これは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()
}
誰かがそれを必要とする場合、これは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()
}