【问题标题】:Safely fixing: javax.net.ssl.SSLPeerUnverifiedException: No peer certificate安全修复:javax.net.ssl.SSLPeerUnverifiedException:没有对等证书
【发布时间】:2013-08-10 04:28:25
【问题描述】:

关于这个问题的帖子有很多(javax.net.ssl.SSLPeerUnverifiedException: No peer certificate),但我没有找到任何适合我的帖子。

许多帖子(如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 certificate is not trusted - on mobile only)

【问题讨论】:

标签: android ssl-certificate


【解决方案1】:

试试下面的代码:-

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

【讨论】:

  • 刚刚试了一下,虽然使用了 HttpGet 还是会发生
  • 但这对我来说很重要
  • 酷。我也有适用于 https 的应用程序,但这次不是,这就是我问这个问题的原因
【解决方案2】:

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

SSL certificate is not trusted - on mobile only

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

【讨论】:

    【解决方案3】:

    就我而言,过去一切正常。两天后突然我的设备没有显示任何 https 站点或图像链接。

    经过一番调查,结果发现我的时间设置在设备上不是最新的。

    我正确地更改了我的时间设置并且它起作用了。

    【讨论】:

      【解决方案4】:

      当我使用自签名证书 + 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 文件夹中进行调试/发布。

      【讨论】:

        猜你喜欢
        • 2015-05-05
        • 1970-01-01
        • 1970-01-01
        • 2017-08-04
        • 1970-01-01
        • 2014-11-22
        • 2015-07-25
        • 2012-11-09
        • 1970-01-01
        相关资源
        最近更新 更多