34

关于这个问题有几十篇文章(javax.net.ssl.SSLPeerUnverifiedException:没有对等证书),但我没有找到任何适合我的东西。

许多帖子(如thisthis)通过允许接受所有证书来“解决”这个问题,但当然,这对于测试以外的任何事情都不是一个好的解决方案。

其他人似乎很本地化,不适合我。我真的希望有人对我缺乏一些见解。

所以,我的问题:我正在通过 HTTPS 连接的只能通过本地网络访问的服务器上进行测试。通过浏览器拨打我需要的电话工作正常。没有抱怨证书,如果你检查证书,一切看起来都很好。

当我在我的 Android 设备上尝试时,我得到javax.net.ssl.SSLPeerUnverifiedException: No peer certificate

这是调用它的代码:

StringBuilder builder = new StringBuilder();
builder.append( /* stuff goes here*/ );

httpGet.setEntity(new UrlEncodedFormEntity(nameValuePairs));
ResponseHandler<String> responseHandler = new BasicResponseHandler();

// Execute HTTP Post Request. Response body returned as a string
HttpClient httpClient = MyActivity.getHttpClient();
HttpGet httpGet = new HttpGet(builder.toString());

String jsonResponse = httpClient.execute(httpGet, responseHandler); //Line causing the Exception

我的代码MyActivity.getHttpClient()

protected synchronized static HttpClient getHttpClient(){
    if (httpClient != null)
        return httpClient;

    HttpParams httpParameters = new BasicHttpParams();
    HttpConnectionParams.setConnectionTimeout(httpParameters, TIMEOUT_CONNECTION);
    HttpConnectionParams.setSoTimeout(httpParameters, TIMEOUT_SOCKET);
    HttpProtocolParams.setVersion(httpParameters, HttpVersion.HTTP_1_1);

    //Thread safe in case various AsyncTasks try to access it concurrently
    SchemeRegistry schemeRegistry = new SchemeRegistry();
    schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
    schemeRegistry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
    ClientConnectionManager cm = new ThreadSafeClientConnManager(httpParameters, schemeRegistry);

    httpClient = new DefaultHttpClient(cm, httpParameters);

    CookieStore cookieStore = httpClient.getCookieStore();
    HttpContext localContext = new BasicHttpContext();
    localContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore);

    return httpClient;
}

任何帮助将非常感激。

编辑

还只是提到我在另一个应用程序中遇到了其他 SSL 问题,但添加该SchemeRegistry部分之前已为我修复了它。

编辑 2

到目前为止,我只在 Android 3.1 上进行了测试,但无论如何我都需要它才能在 Android 2.2+ 上运行。我刚刚在我的 Android 标签(Android 3.1)上的浏览器上进行了测试,它抱怨证书。在我的电脑浏览器上很好,但在 Android 浏览器或我的应用程序中不行。

编辑 3

原来iOS浏览器也抱怨它。我开始认为这是此处描述的证书链问题(SSL 证书不受信任 - 仅在移动设备上

4

4 回答 4

20

事实证明我的代码很好,问题是服务器没有返回完整的证书链。有关更多信息,请参阅此 SO 帖子和此超级用户帖子:

SSL 证书不受信任 - 仅在移动设备上

https://superuser.com/questions/347588/how-do-ssl-chains-work

于 2013-08-13T13:29:14.003 回答
6

试试下面的代码: -

        BasicHttpResponse httpResponse = null;

        HttpPost httppost = new HttpPost(URL);

        HttpParams httpParameters = new BasicHttpParams();
        // Set the timeout in milliseconds until a connection is
        // established.
        int timeoutConnection = ConstantLib.CONNECTION_TIMEOUT;
        HttpConnectionParams.setConnectionTimeout(httpParameters,
                timeoutConnection);
        // Set the default socket timeout (SO_TIMEOUT)
        // in milliseconds which is the timeout for waiting for data.
        int timeoutSocket = ConstantLib.CONNECTION_TIMEOUT;
        HttpConnectionParams
                .setSoTimeout(httpParameters, timeoutSocket);

        DefaultHttpClient httpClient = new DefaultHttpClient(
                httpParameters);
        List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
        nameValuePairs.add(new BasicNameValuePair(ConstantLib.locale,
                locale));
于 2013-08-12T06:43:45.653 回答
6

In my case everything used to work fine. Suddenly after 2 days my device did not show any https site or image link.

After some investigation it turns out that My time settings was not up to date on device.

I changed my time settings properly and it worked.

于 2016-02-28T11:15:57.150 回答
-1

当我使用自签名证书 + ip 地址时,我遇到了这个异常。只需添加这些行

HostnameVerifier allHostsValid = new HostnameVerifier() {
            @Override
            public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        };
HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);

并且您的 HttpURLConnection 将起作用。该技巧与针对 CA 的验证无关!因此,如果我指定错误的 CA 并使用该技巧,我将得到另一个异常。所以主机仍然值得信赖

以防万一,我将在此处留下用于指定您自己的 CA 的代码:

String certStr = context.getString(R.string.caApi);
X509Certificate ca = SecurityHelper.readCert(certStr);

TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(null);
ks.setCertificateEntry("caCert", ca);

tmf.init(ks);

SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), null);
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());

不要忘记使用很酷的功能 buildTypes 并将不同的 CA 放置在 res 文件夹中进行调试/发布。

于 2017-11-13T21:34:37.597 回答