出于测试目的,我正在尝试将套接字工厂添加到我的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
来匹配它.
有没有人能够生成一个SSLContext实现,它可以在不使用Apache HttpClient的情况下完成我想做的事情?
万一有人落在这里,对我有用的(唯一)解决方案就是创造这里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); } }
不推荐使用以下方法
sslSocketFactory(SSLSocketFactory sslSocketFactory)
考虑将其更新为
sslSocketFactory(SSLSocketFactory sslSocketFactory, X509TrustManager trustManager)
更新okhttp3.0,getAcceptedIssuers()函数必须返回一个空数组而不是null
SSLSocketFactory不公开其X509TrustManager,这是OkHttp需要构建一个干净的证书链的字段.相反,此方法必须使用反射来提取信任管理器.应用程序应该更喜欢调用sslSocketFactory(SSLSocketFactory,X509TrustManager),这样可以避免这种反射.
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[]{}; } });
如果有人需要,这是sonxurxo在Kotlin的解决方案。
private fun getUnsafeOkHttpClient(): OkHttpClient { // Create a trust manager that does not validate certificate chains val trustAllCerts = arrayOf(object : X509TrustManager { override fun checkClientTrusted(chain: Array ?, authType: String?) { } override fun checkServerTrusted(chain: Array ?, authType: String?) { } override fun getAcceptedIssuers() = arrayOf () }) // 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() }