Android 使用 okHttp 信任所有证书
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25509296/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Trusting all certificates with okHttp
提问by seato
For testing purposes, I'm trying to add a socket factory to my okHttp client that trusts everything while a proxy is set. This has been done many times over, but my implementation of a trusting socket factory seems to be missing something:
出于测试目的,我正在尝试向我的 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);
No requests are being sent out of my app and no exceptions are getting logged so it seems that it's failing silently within okHttp. Upon further investigation, it seems that there is an Exception being swallowed up in okHttp's Connection.upgradeToTls()
when the handshake is being forced. The exception I'm being given is: javax.net.ssl.SSLException: SSL handshake terminated: ssl=0x74b522b0: SSL_ERROR_ZERO_RETURN occurred. You should never see this.
我的应用程序没有发出任何请求,也没有记录任何异常,因此它似乎在 okHttp 中默默地失败了。经过进一步调查,似乎Connection.upgradeToTls()
在强制握手时,okHttp's中有一个异常被吞噬。我得到的例外是:javax.net.ssl.SSLException: SSL handshake terminated: ssl=0x74b522b0: SSL_ERROR_ZERO_RETURN occurred. You should never see this.
The following code produces an SSLContext
which works like a charm in creating an SSLSocketFactory that doesn't throw any exceptions:
下面的代码生成一个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();
}
The issue is that I'm trying to remove all Apache HttpClient dependencies from my app completely. The underlying code with Apache HttpClient to produce the SSLContext
seems straightforward enough, but I'm obviously missing something as I cannot configure my SSLContext
to match this.
问题是我试图从我的应用程序中完全删除所有 Apache HttpClient 依赖项。使用 Apache HttpClient 生成的底层代码SSLContext
似乎很简单,但我显然缺少一些东西,因为我无法配置我的SSLContext
来匹配它。
Would anyone be able to produce an SSLContext implementation which does what I'd like without using Apache HttpClient?
有没有人能够在不使用 Apache HttpClient 的情况下生成一个 SSLContext 实现来做我想做的事情?
回答by sonxurxo
Just in case anyone falls here, the (only) solution that worked for me is creating the OkHttpClient
like explained here.
以防万一有人跌倒,对我有用的(唯一)解决方案是创建此处OkHttpClient
解释的类似内容。
Here is the code:
这是代码:
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);
}
}
回答by Jakub N
Following method is deprecated
以下方法已弃用
sslSocketFactory(SSLSocketFactory sslSocketFactory)
Consider updating it to
考虑将其更新为
sslSocketFactory(SSLSocketFactory sslSocketFactory, X509TrustManager trustManager)
回答by Ervin Zhang
Update OkHttp 3.0, the getAcceptedIssuers()
function must return an empty arrayinstead of null
.
更新 OkHttp 3.0,该getAcceptedIssuers()
函数必须返回一个空数组而不是null
.
回答by Tharindu Bandara
SSLSocketFactory does not expose its X509TrustManager, which is a field that OkHttp needs to build a clean certificate chain. This method instead must use reflection to extract the trust manager. Applications should prefer to call sslSocketFactory(SSLSocketFactory, X509TrustManager), which avoids such reflection.
SSLSocketFactory 不会暴露其 X509TrustManager,这是 OkHttp 构建干净证书链所需的字段。此方法必须使用反射来提取信任管理器。应用程序应该更喜欢调用 sslSocketFactory(SSLSocketFactory, X509TrustManager),这样可以避免这种反射。
Source: OkHttp documentation
来源: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[]{};
}
});
回答by doodla
This is sonxurxo's solution in Kotlin, if anyone needs it.
如果有人需要,这是在 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()
}
回答by George Shalvashvili
I made an extension function for Kotlin. Paste it where ever you like and import it while creating OkHttpClient
.
我为 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
}
use it like this:
像这样使用它:
val okHttpClient = OkHttpClient.Builder().apply {
// ...
if (BuildConfig.DEBUG) //if it is a debug build ignore ssl errors
ignoreAllSSLErrors()
//...
}.build()
回答by netta
This is the Scala solution if anyone needs it
如果有人需要,这是 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()
}
}
回答by Tony Trummer
You should never look to override certificate validation in code! If you need to do testing, use an internal/test CA and install the CA root certificate on the device or emulator. You can use BurpSuite or Charles Proxy if you don't know how to setup a CA.
您永远不应该在代码中覆盖证书验证!如果您需要进行测试,请使用内部/测试 CA 并在设备或模拟器上安装 CA 根证书。如果您不知道如何设置 CA,您可以使用 BurpSuite 或 Charles Proxy。