安全修复:javax.net.ssl.SSLPeerUnverifiedException:没有对等证书

时间:2013-08-08 12:44:25

标签: android ssl-certificate

有很多关于这个问题的帖子(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 certificate is not trusted - on mobile only

4 个答案:

答案 0 :(得分:19)

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

SSL certificate is not trusted - on mobile only

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

答案 1 :(得分:5)

尝试以下代码: -

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

答案 2 :(得分:5)

在我的情况下,一切都工作得很好。 2天后,我的设备突然没有显示任何https站点或图像链接。

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

我正确地更改了时间设置并且运行正常。

答案 3 :(得分:-1)

我使用自签名证书+ IP地址时遇到此异常。只需添加这些行

$successful_login = false;

$query = 'SELECT password FROM user WHERE UserID = ?';
$stmt = mysqli_prepare($con, $query);
$stmt->bind_param('s', $userid);
$stmt->bind_result($row_passwd);

$stmt->execute();

if ($stmt->fetch()) {
    $successful_login = password_verify($password, $row_passwd);
}

if ($successful_login) {
    echo 'Account validated.';
}

你的HttpURLConnection会起作用。 这个技巧与CA的验证无关!因此,如果我指定错误的CA并使用该技巧,我将得到另一个例外。所以主持人仍然值得信赖

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

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

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

相关问题