【问题标题】:OkHttp trusting certificateOkHttp 信任证书
【发布时间】:2016-01-09 02:53:05
【问题描述】:

在我的 android 应用程序中,我需要使用 OkHttp 库向我的服务器执行一些请求。 我有一个包含四个部分的 ssl 证书:

  • AddTrustExternalCARoot.crt
  • COMODORSAAddTrustCA.crt
  • COMODORSADomainValidationSecureServerCA.crt
  • www_mydomain_com.crt

我已经在 portecle 1.9 中导入了所有部件,然后我设置了我的密钥库密码并导出了 .bks 证书。

然后我将这个 mycert.bks 插入到我的应用项目的 res/raw 文件夹中。 现在我正在尝试使用以下代码通过 https 连接到我的服务器:

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

但我得到一个异常,这是 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)

问题出在哪里?

更新: 我在这个库上做了很多尝试,我发现了这一点:

  • 如果我自动向 https:\link.com OkHttp 库发出请求 信任所有证书。
  • 如果我只想信任我的证书,我必须执行我认为的解决方案 贴在上面。
  • 如果我不想接受所有主机,但不使用我的证书,我 可以按照 BNK 的建议使用 hostnameVerifier。

但是,如果我的解决方案有效,为什么我会发布这个问题?因为我很愚蠢,我向我的 vps url (vpsxxx.net/directory.php) 而不是我的域 (mydomain.it/directory.php) 发出请求。

显然 SSL 证书应用于我的域而不是我的 vps。

我希望这对某人有用。

P.S.:对不起我的英语! :D

【问题讨论】:

    标签: android ssl https keystore okhttp


    【解决方案1】:

    假设您的服务器应用托管在具有服务器证书的服务器计算机中,例如,"Issued to""localhost"。然后,在verify 方法中,您可以验证"localhost"

    HostnameVerifier hostnameVerifier = new HostnameVerifier() {
        @Override
        public boolean verify(String hostname, SSLSession session) {
            HostnameVerifier hv =
                HttpsURLConnection.getDefaultHostnameVerifier();
            return hv.verify("localhost", session);
        }
    };
    

    您可以在以下链接阅读更多内容:

    1. HostnameVerifier

      如果 URL 的主机名与对等方的标识主机名不匹配,则在握手期间使用它。

    2. Common Problems with Hostname Verification

      发生这种情况的一个原因是服务器配置错误。这 服务器配置了没有主题的证书 或与您所在的服务器匹配的主题备用名称字段 试图到达...

    然后,您可以通过调用client.setHostnameVerifier(hostnameVerifier); 在您的应用中使用主机名验证程序。希望这会有所帮助!

    P/S:另一个临时解决方法是在 verify 方法中使用 return true;,但是不建议这样做。

    【讨论】:

    • 为什么不在verify() 中返回true
    猜你喜欢
    • 2014-10-19
    • 2019-06-18
    • 2020-02-13
    • 2019-07-25
    • 2018-02-20
    • 2016-09-28
    • 2013-06-04
    • 2017-08-15
    • 1970-01-01
    相关资源
    最近更新 更多