通过https发送POST请求时SSLHandshakeException

时间:2018-02-23 11:43:55

标签: android https sslhandshakeexception httpsurlconnection

我尝试向远程安全服务器发送POST请求(https调用)。 首先,我使用OkHTTP lib进行调用,因为这个lib可以在之前的应用程序中进行http调用,但是使用https它不再起作用,请参阅我之前的帖子:Cannot make HTTPS calls with OKHTTP lib

我决定尝试使用HttpURLConnection进行调用,如下所述:https://developer.android.com/reference/java/net/HttpURLConnection.html 我使用的代码仅适用于某些设备。

它适用于配备SIM卡和wifi的Android 6.0上的Wiko,并且不适用于仅通过Wifi链接到互联网的Android 4.2.2上的三星。

这是我遇到的问题的logcat:

02-23 12:29:59.893 11026-11951 W/System.err: javax.net.ssl.SSLHandshakeException: com.android.org.bouncycastle.jce.exception.ExtCertPathValidatorException: Could not validate certificate signature.
02-23 12:29:59.923 11026-11951 W/System.err:     at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:382)
02-23 12:29:59.923 11026-11951 W/System.err:     at libcore.net.http.HttpConnection.setupSecureSocket(HttpConnection.java:231)
02-23 12:29:59.923 11026-11951 W/System.err:     at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.makeSslConnection(HttpsURLConnectionImpl.java:478)
02-23 12:29:59.923 11026-11951 W/System.err:     at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.connect(HttpsURLConnectionImpl.java:433)
02-23 12:29:59.923 11026-11951 W/System.err:     at libcore.net.http.HttpEngine.sendSocketRequest(HttpEngine.java:290)
02-23 12:29:59.923 11026-11951 W/System.err:     at libcore.net.http.HttpEngine.sendRequest(HttpEngine.java:240)
02-23 12:29:59.923 11026-11951 W/System.err:     at libcore.net.http.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:81)
02-23 12:29:59.923 11026-11951 W/System.err:     at libcore.net.http.HttpURLConnectionImpl.getOutputStream(HttpURLConnectionImpl.java:197)
02-23 12:29:59.923 11026-11951 W/System.err:     at libcore.net.http.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:281)
02-23 12:29:59.923 11026-11951 W/System.err:     at com.gulplug.gulplugtoolbox.DiagnosisOnline$NetworkAsyncTask.doInBackground(DiagnosisOnline.java:109)
02-23 12:29:59.923 11026-11951 W/System.err:     at com.gulplug.gulplugtoolbox.DiagnosisOnline$NetworkAsyncTask.doInBackground(DiagnosisOnline.java:82)
02-23 12:29:59.923 11026-11951 W/System.err:     at android.os.AsyncTask$2.call(AsyncTask.java:287)
02-23 12:29:59.923 11026-11951 W/System.err:     at java.util.concurrent.FutureTask.run(FutureTask.java:234)
02-23 12:29:59.923 11026-11951 W/System.err:     at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
02-23 12:29:59.923 11026-11951 W/System.err:     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
02-23 12:29:59.923 11026-11951 W/System.err:     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
02-23 12:29:59.933 11026-11951 W/System.err:     at java.lang.Thread.run(Thread.java:856)
02-23 12:29:59.933 11026-11951 W/System.err: Caused by: java.security.cert.CertificateException: com.android.org.bouncycastle.jce.exception.ExtCertPathValidatorException: Could not validate certificate signature.
02-23 12:29:59.933 11026-11951 W/System.err:     at org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:296)
02-23 12:29:59.933 11026-11951 W/System.err:     at org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.checkServerTrusted(TrustManagerImpl.java:197)
02-23 12:29:59.933 11026-11951 W/System.err:     at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.verifyCertificateChain(OpenSSLSocketImpl.java:598)
02-23 12:29:59.933 11026-11951 W/System.err:     at org.apache.harmony.xnet.provider.jsse.NativeCrypto.SSL_do_handshake(Native Method)
02-23 12:29:59.933 11026-11951 W/System.err:     at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:379)
02-23 12:29:59.933 11026-11951 W/System.err:    ... 16 more
02-23 12:29:59.933 11026-11951 W/System.err: Caused by: com.android.org.bouncycastle.jce.exception.ExtCertPathValidatorException: Could not validate certificate signature.
02-23 12:29:59.943 11026-11951 W/System.err:     at com.android.org.bouncycastle.jce.provider.RFC3280CertPathUtilities.processCertA(RFC3280CertPathUtilities.java:1475)
02-23 12:29:59.943 11026-11951 W/System.err:     at com.android.org.bouncycastle.jce.provider.PKIXCertPathValidatorSpi.engineValidate(PKIXCertPathValidatorSpi.java:305)
02-23 12:29:59.943 11026-11951 W/System.err:     at com.sec.android.security.pkix.SecCertPathValidatorSpi.engineValidate(SecCertPathValidatorSpi.java:99)
02-23 12:29:59.953 11026-11951 W/System.err:     at java.security.cert.CertPathValidator.validate(CertPathValidator.java:190)
02-23 12:29:59.953 11026-11951 W/System.err:     at org.apache.harmony.xnet.provider.jsse.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:283)
02-23 12:29:59.953 11026-11951 W/System.err:    ... 20 more
02-23 12:29:59.953 11026-11951 W/System.err: Caused by: java.security.SignatureException: Signature was not verified
02-23 12:29:59.953 11026-11951 W/System.err:     at org.apache.harmony.security.provider.cert.X509CertImpl.verify(X509CertImpl.java:384)
02-23 12:29:59.953 11026-11951 W/System.err:     at com.android.org.bouncycastle.jce.provider.CertPathValidatorUtilities.verifyX509Certificate(CertPathValidatorUtilities.java:1428)
02-23 12:29:59.953 11026-11951 W/System.err:     at com.android.org.bouncycastle.jce.provider.RFC3280CertPathUtilities.processCertA(RFC3280CertPathUtilities.java:1470)
02-23 12:29:59.953 11026-11951 W/System.err:    ... 24 more

以及附加到此日志的代码:

class NetworkAsyncTask extends AsyncTask<Void, Void, Void> {
    @Override
    protected Void doInBackground(Void... voids) {
        Authentification authentification = new Authentification();
        authentification.setApplicationToken(applicationtoken);
        Gson gson = new Gson();
        //String json = gson.toJson(authentification);
        String json = "";
        Log.d(TAG, json);
        JSONObject auth = new JSONObject();
        try {
            auth.put("application_token",mytoken);
        } catch (JSONException e) {
            e.printStackTrace();
        }
        String url = myurl;

        try {
            URL object = new URL(url);
            HttpsURLConnection con = (HttpsURLConnection) object.openConnection();

            con.setDoOutput(true);
            con.setDoInput(true);
            con.setRequestProperty("Content-Type", "application/json");
            con.setRequestProperty("Accept", "application/json");
            con.setRequestProperty("Content-Lenght", String.valueOf(json.getBytes("UTF-8").length));
            con.setRequestMethod("POST");
            con.setSSLSocketFactory((SSLSocketFactory) SSLSocketFactory.getDefault());

            OutputStreamWriter wr = null;
            wr = new OutputStreamWriter(con.getOutputStream());
            wr.write(auth.toString());
            wr.flush();

            StringBuilder sb = new StringBuilder();
            int HttpResult = 0;

            HttpResult = con.getResponseCode();

            if (HttpResult == HttpURLConnection.HTTP_OK) {
                BufferedReader br = new BufferedReader(
                        new InputStreamReader(con.getInputStream(), "utf-8"));
                String line = null;
                while ((line = br.readLine()) != null) {
                    sb.append(line + "\n");
                }
                br.close();
                Log.d(TAG, "First log");
                Log.d(TAG, "" + sb.toString());
            } else {
                Log.d(TAG, "response code : " + HttpResult);
                Log.d(TAG, "Http not ok");
                Log.d(TAG, con.getResponseMessage());
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
}

我不明白为什么我的第一台设备可以验证签名而另一台设备无法验证签名。 我尝试按照此处的说明同步日期和时间:Could not validate certificate signature?

这里可能有我的问题的解释,但我没有得到https://groups.google.com/forum/#!topic/android-security-discuss/C_cm3k9SdaM

有人遇到同样的问题并修复了吗?

UPDT: Alex和Anton提供的两种方法都不适用于我的设备。 使用Google Play服务表示该提供商是最新的。当使用此处描述的方法启用TLS 1.1和1.2时,我仍然没有得到签名验证:https://blog.dev-area.net/2015/08/13/android-4-1-enable-tls-1-1-and-tls-1-2/

UPDT 2: 在此链接之后,服务器应使用TLS 1.1:https://www.ssllabs.com TLS enabled

4 个答案:

答案 0 :(得分:2)

正如Anton Malyshev所说,Android 4.2.2不支持TLS v1.2,事实上在Android 5.0以下的设备上,即使它在某些设备上受支持,你也会遇到不推荐使用的问题证书。

如果设备具有播放服务,您可以尝试安装google ssl提供程序。

您可以阅读更多相关信息 https://developer.android.com/training/articles/security-gms-provider.html

答案 1 :(得分:1)

旧设备上的Android 4.2.2根本不支持服务器上使用的新TLS版本。您需要允许在您的服务器上至少使用TLS 1.1,在客户端无需执行任何操作。

UPD :Android&lt; 5上默认情况下未启用TLS 1.2支持,但您可以使用自定义SSLSocketFactory启用其使用,包括以下方法:

private Socket enableTLSOnSocket(Socket socket) {
    if(socket != null && (socket instanceof SSLSocket)) {
        ((SSLSocket)socket).setEnabledProtocols(new String[] {"TLSv1.1", "TLSv1.2"});
    }
    return socket;
}

请参阅参考链接:https://blog.dev-area.net/2015/08/13/android-4-1-enable-tls-1-1-and-tls-1-2/

答案 2 :(得分:1)

我能够使用OkHttp和Retrofit2实现这一目标。它是用科特林写的。

您可以在启动器活动中启动应用时添加此功能:

    try {
           SSLContext.getInstance("TLSv1.2")
        } catch (e: NoSuchAlgorithmException) {
            e.printStackTrace()
        }

        try {
            ProviderInstaller.installIfNeeded(context)
        } catch (e: Exception) {
            e.printStackTrace()
        }

还要在OkHttp Builder上添加:

fun provideSecureClient(): OkHttpClient {

    try {
        val trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
        trustManagerFactory.init(null as KeyStore?)
        val trustManagers = trustManagerFactory.trustManagers
        if (trustManagers.size != 1 || trustManagers[0] !is X509TrustManager) {
            throw IllegalStateException("Unexpected default trust managers:" + Arrays.toString(trustManagers))
        }

        val trustManager = trustManagers[0] as X509TrustManager
        val sslContext = SSLContext.getInstance("SSL")
        sslContext.init(null, arrayOf<TrustManager>(trustManager), null)
        val sslSocketFactory = sslContext.socketFactory

        return OkHttpClient.Builder()
                .sslSocketFactory(sslSocketFactory, trustManager)
                .build()

    } catch (e: Exception) {
        throw RuntimeException(e)
    }

}

答案 3 :(得分:1)

this.props.user

在调用任何HTTP之前调用上面的方法。

在gradle中添加到库下面:

...
constructor(props) {
    super(props);
    this.state = {
    language: this.props.user && this.props.user.language || '',
    description: this.props.user && this.props.user.description || ''
   }
...
componentWillReceiveProps(nextProps) {
    if (nextProps.user) {
        this.setState({
            language: nextProps.user.language,
            description: nextProps.user.description
        })
    }
}