OkHttp 信任证书 [英] OkHttp trusting certificate
问题描述
在我的 android 应用程序中,我需要使用 OkHttp 库向我的服务器执行一些请求.我有一个由四部分组成的 ssl 证书:
- AddTrustExternalCARoot.crt
- COMODORSAAddTrustCA.crt
- COMODORSADomainValidationSecureServerCA.crt
- www_mydomain_com.crt
我已经在 portecle 1.9 中导入了所有部分,然后我设置了我的密钥库密码并导出了 .bks 证书.
然后我将这个 mycert.bks 插入到我的应用项目的 res/raw 文件夹中.现在我正在尝试使用以下代码通过 https 连接到我的服务器:
OkHttpClient 客户端 = new OkHttpClient();尝试{client.setSslSocketFactory(getPinnedCertSslSocketFactory(context));RequestBody formBody = new FormEncodingBuilder().add("参数", "xxx").建造();请求请求 = new Request.Builder().url("https:\mydomain.com").post(formBody).建造();响应 response = client.newCall(request).execute();if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);返回 response.body().string();;} 捕获(异常 e){e.printStackTrace();}返回空;}私有 SSLSocketFactory getPinnedCertSslSocketFactory(上下文上下文){尝试 {KeyStore 信任 = KeyStore.getInstance("BKS");InputStream in = context.getResources().openRawResource(R.raw.mycert);信任.加载(在,我的通行证".toCharArray());SSLContext sslContext = SSLContext.getInstance("TLS");TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());trustManagerFactory.init(可信);sslContext.init(null, trustManagerFactory.getTrustManagers(), null);返回 sslContext.getSocketFactory();} 捕获(异常 e){Log.e("MyApp", e.getMessage(), e);}返回空;}
但是我得到了一个异常,这是 logcat:
10-11 18:22:51.930 13604-5341/com.aaa.android.client W/System.err: javax.net.ssl.SSLPeerUnverifiedException: 主机名 myserver.net 未验证:10-11 18:22:51.930 13604-5341/com.aaa.android.client W/System.err:证书:sha1/mysha1string"10-11 18:22:51.930 13604-5341/com.aaa.android.client W/System.err: DN: CN=www.aaa.it,OU=PositiveSSL,OU=域控制验证10-11 18:22:51.930 13604-5341/com.aaa.android.client W/System.err: subjectAltNames: [www.aaa.it, aaa.it]10-11 18:22:51.940 13604-5341/com.aaa.android.client W/System.err: 在 com.squareup.okhttp.Connection.connectTls(Connection.java:244)10-11 18:22:51.940 13604-5341/com.aaa.android.client W/System.err:在 com.squareup.okhttp.Connection.connectSocket(Connection.java:199)10-11 18:22:51.940 13604-5341/com.aaa.android.client W/System.err: 在 com.squareup.okhttp.Connection.connect(Connection.java:172)10-11 18:22:51.940 13604-5341/com.aaa.android.client W/System.err: 在 com.squareup.okhttp.Connection.connectAndSetOwner(Connection.java:367)10-11 18:22:51.940 13604-5341/com.aaa.android.client W/System.err: 在 com.squareup.okhttp.OkHttpClient$1.connectAndSetOwner(OkHttpClient.java:128)10-11 18:22:51.940 13604-5341/com.aaa.android.client W/System.err: 在 com.squareup.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:328)10-11 18:22:51.940 13604-5341/com.aaa.android.client W/System.err: 在 com.squareup.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:245)10-11 18:22:51.940 13604-5341/com.aaa.android.client W/System.err:在 com.squareup.okhttp.Call.getResponse(Call.java:267)10-11 18:22:51.940 13604-5341/com.aaa.android.client W/System.err: 在 com.squareup.okhttp.Call$ApplicationInterceptorChain.proceed(Call.java:224)10-11 18:22:51.940 13604-5341/com.aaa.android.client W/System.err: 在 com.squareup.okhttp.Call.getResponseWithInterceptorChain(Call.java:195)10-11 18:22:51.940 13604-5341/com.aaa.android.client W/System.err:在 com.squareup.okhttp.Call.execute(Call.java:79)10-11 18:22:51.940 13604-5341/com.aaa.android.client W/System.err: 在 com.aaa.android.client.Login$BackgroundTask.doInBackground(Login.java:294)10-11 18:22:51.940 13604-5341/com.aaa.android.client W/System.err: 在 com.aaa.android.client.Login$BackgroundTask.doInBackground(Login.java:277)10-11 18:22:51.950 13604-5341/com.aaa.android.client W/System.err:在 android.os.AsyncTask$2.call(AsyncTask.java:288)10-11 18:22:51.950 13604-5341/com.aaa.android.client W/System.err:在 java.util.concurrent.FutureTask.run(FutureTask.java:237)10-11 18:22:51.950 13604-5341/com.aaa.android.client W/System.err:在 android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)10-11 18:22:51.950 13604-5341/com.aaa.android.client W/System.err: 在 java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)10-11 18:22:51.950 13604-5341/com.aaa.android.client W/System.err:在 java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)10-11 18:22:51.950 13604-5341/com.aaa.android.client W/System.err: 在 java.lang.Thread.run(Thread.java:818)
问题出在哪里?
更新:我在这个库上做了很多尝试,我发现了这一点:
- 如果我自动向 https:link.com OkHttp 库发出请求信任所有证书.
- 如果我只想信任我的证书,我必须执行以下解决方案贴在上面.
- 如果我不想接受所有主机,但不使用我的证书,我可以按照 BNK 的建议使用 hostnameVerifier.
但是如果我的解决方案有效,为什么我发布了这个问题?因为我很笨,我对我的 vps url (vpsxxx.net/directory.php) 而不是我的域 (mydomain.it/directory.php) 做了请求.
显然 SSL 证书应用于我的域而不是我的 vps.
我希望这对某人有用.
P.S.:对不起我的英语!:D
让我们假设您的服务器应用程序托管在一台服务器机器内,该机器有一个服务器证书,其中 "Issued to"
是 例如本地主机"
.然后,在 verify
方法中,您可以验证 "localhost"
.
HostnameVerifier hostnameVerifier = new HostnameVerifier() {@覆盖公共布尔验证(字符串主机名,SSLSession 会话){主机名验证器 hv =HttpsURLConnection.getDefaultHostnameVerifier();返回 hv.verify("localhost", session);}};
您可以通过以下链接阅读更多信息:
- <块引用>
如果 URL 的主机名与对等方的标识主机名不匹配,它将在握手期间使用.
主机名验证的常见问题><块引用>
发生这种情况的一个原因是服务器配置错误.这服务器配置了没有主题的证书或与您所在的服务器匹配的主题备用名称字段试图达到...
然后,您可以通过调用 client.setHostnameVerifier(hostnameVerifier);
在您的应用程序中使用主机名验证器.希望这会有所帮助!
P/S:另一个临时解决方法是 return true;
在 verify
方法中,但不推荐这样做.
In my android app I need to execute some request to my server with OkHttp library. I have a ssl certificate that consist in four parts:
- AddTrustExternalCARoot.crt
- COMODORSAAddTrustCA.crt
- COMODORSADomainValidationSecureServerCA.crt
- www_mydomain_com.crt
I have imported all parts in portecle 1.9, then I set my keystore password and I have exported the .bks cert.
Then I have inserted this mycert.bks in res/raw folder of my app project. Now I'm trying to connect to my server by https with this code:
OkHttpClient client = new OkHttpClient();
try{
client.setSslSocketFactory(getPinnedCertSslSocketFactory(context));
RequestBody formBody = new FormEncodingBuilder()
.add("params", "xxx")
.build();
Request request = new Request.Builder()
.url("https:\mydomain.com")
.post(formBody)
.build();
Response response = client.newCall(request).execute();
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
return response.body().string();;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private SSLSocketFactory getPinnedCertSslSocketFactory(Context context) {
try {
KeyStore trusted = KeyStore.getInstance("BKS");
InputStream in = context.getResources().openRawResource(R.raw.mycert);
trusted.load(in, "mypass".toCharArray());
SSLContext sslContext = SSLContext.getInstance("TLS");
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(trusted);
sslContext.init(null, trustManagerFactory.getTrustManagers(), null);
return sslContext.getSocketFactory();
} catch (Exception e) {
Log.e("MyApp", e.getMessage(), e);
}
return null;
}
But I obtain an exception, this is the logcat:
10-11 18:22:51.930 13604-5341/com.aaa.android.client W/System.err: javax.net.ssl.SSLPeerUnverifiedException: Hostname myserver.net not verified:
10-11 18:22:51.930 13604-5341/com.aaa.android.client W/System.err: certificate: sha1/"mysha1string"
10-11 18:22:51.930 13604-5341/com.aaa.android.client W/System.err: DN: CN=www.aaa.it,OU=PositiveSSL,OU=Domain Control Validated
10-11 18:22:51.930 13604-5341/com.aaa.android.client W/System.err: subjectAltNames: [www.aaa.it, aaa.it]
10-11 18:22:51.940 13604-5341/com.aaa.android.client W/System.err: at com.squareup.okhttp.Connection.connectTls(Connection.java:244)
10-11 18:22:51.940 13604-5341/com.aaa.android.client W/System.err: at com.squareup.okhttp.Connection.connectSocket(Connection.java:199)
10-11 18:22:51.940 13604-5341/com.aaa.android.client W/System.err: at com.squareup.okhttp.Connection.connect(Connection.java:172)
10-11 18:22:51.940 13604-5341/com.aaa.android.client W/System.err: at com.squareup.okhttp.Connection.connectAndSetOwner(Connection.java:367)
10-11 18:22:51.940 13604-5341/com.aaa.android.client W/System.err: at com.squareup.okhttp.OkHttpClient$1.connectAndSetOwner(OkHttpClient.java:128)
10-11 18:22:51.940 13604-5341/com.aaa.android.client W/System.err: at com.squareup.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:328)
10-11 18:22:51.940 13604-5341/com.aaa.android.client W/System.err: at com.squareup.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:245)
10-11 18:22:51.940 13604-5341/com.aaa.android.client W/System.err: at com.squareup.okhttp.Call.getResponse(Call.java:267)
10-11 18:22:51.940 13604-5341/com.aaa.android.client W/System.err: at com.squareup.okhttp.Call$ApplicationInterceptorChain.proceed(Call.java:224)
10-11 18:22:51.940 13604-5341/com.aaa.android.client W/System.err: at com.squareup.okhttp.Call.getResponseWithInterceptorChain(Call.java:195)
10-11 18:22:51.940 13604-5341/com.aaa.android.client W/System.err: at com.squareup.okhttp.Call.execute(Call.java:79)
10-11 18:22:51.940 13604-5341/com.aaa.android.client W/System.err: at com.aaa.android.client.Login$BackgroundTask.doInBackground(Login.java:294)
10-11 18:22:51.940 13604-5341/com.aaa.android.client W/System.err: at com.aaa.android.client.Login$BackgroundTask.doInBackground(Login.java:277)
10-11 18:22:51.950 13604-5341/com.aaa.android.client W/System.err: at android.os.AsyncTask$2.call(AsyncTask.java:288)
10-11 18:22:51.950 13604-5341/com.aaa.android.client W/System.err: at java.util.concurrent.FutureTask.run(FutureTask.java:237)
10-11 18:22:51.950 13604-5341/com.aaa.android.client W/System.err: at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
10-11 18:22:51.950 13604-5341/com.aaa.android.client W/System.err: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
10-11 18:22:51.950 13604-5341/com.aaa.android.client W/System.err: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
10-11 18:22:51.950 13604-5341/com.aaa.android.client W/System.err: at java.lang.Thread.run(Thread.java:818)
Where is the problem?
UPDATE: I have done a lot of tries on this library and I discovered this:
- If I do a request to https:link.com OkHttp library automatically trust all certificate.
- If I want trust only my certificate, I have to do the solution that I posted above.
- If I doesn't want to accept all host,but without use my certificate I can use hostnameVerifier as BNK suggest.
But why I posted the question if my solution works? Because I'm stupid and I did the request to my vps url (vpsxxx.net/directory.php) and not to my domain (mydomain.it/directory.php).
Obviously the SSL certificate is applied to my domain and not to my vps.
I'll hope that this can be useful for someone.
P.S.: Sorry for my English! :D
Let's assume your server app is hosting inside a server machine which has a server certificate in which "Issued to"
is "localhost"
, for example. Then, inside verify
method you can verify "localhost"
.
HostnameVerifier hostnameVerifier = new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
HostnameVerifier hv =
HttpsURLConnection.getDefaultHostnameVerifier();
return hv.verify("localhost", session);
}
};
You can read more at the following links:
It is to be used during a handshake if the URL's hostname does not match the peer's identification hostname.
Common Problems with Hostname Verification
One reason this can happen is due to a server configuration error. The server is configured with a certificate that does not have a subject or subject alternative name fields that match the server you are trying to reach...
Then, you can use the hostname verifier in your app, by calling client.setHostnameVerifier(hostnameVerifier);
. Hope this helps!
P/S: another temporary workaround is return true;
inside verify
method, however, it's not recommended.
这篇关于OkHttp 信任证书的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!