【问题标题】:Android Failure in SSL library when connecting to my local XAMPP hosted website连接到我的本地 XAMPP 托管网站时,SSL 库中的 Android 失败
【发布时间】:2015-10-08 16:49:15
【问题描述】:

我是任何网络相关编程的新手,所以我知道我正在深入研究,但是我在我的 android HttpsURLConnection 和我的本地 XAMPP 托管网站之间获得成功的 SSL 握手时遇到了问题,而只是一个 php 脚本返回Hello World!首先让我说我可以从我的计算机(主机)和我的安卓手机浏览器(https)加载这个页面。

问题:

当我尝试通过 HttpsURLConnection 将应用程序与我的服务器连接时,我收到以下错误:

System.err﹕ javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x5e522ba8: Failure in SSL library, usually a protocol error
System.err﹕ error:1407743E:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert inappropriate fallback (external/openssl/ssl/s23_clnt.c:744 0x5e5967e8:0x00000000)
System.err﹕ at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:449)
System.err﹕ at com.android.okhttp.Connection.upgradeToTls(Connection.java:146)
System.err﹕ at com.android.okhttp.Connection.connect(Connection.java:107)
System.err﹕ at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:294)
System.err﹕ at com.android.okhttp.internal.http.HttpEngine.sendSocketRequest(HttpEngine.java:255)
System.err﹕ at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:206)
System.err﹕ at com.android.okhttp.internal.http.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:345)
System.err﹕ at com.android.okhttp.internal.http.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:89)
System.err﹕ at com.android.okhttp.internal.http.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:161)
System.err﹕ at yellowgames.battlenetfriendfinder.ServerConnection$TaskExecuter.doInBackground(ServerConnection.java:118)
System.err﹕ at yellowgames.battlenetfriendfinder.ServerConnection$TaskExecuter.doInBackground(ServerConnection.java:94)
System.err﹕ at android.os.AsyncTask$2.call(AsyncTask.java:288)
System.err﹕ at java.util.concurrent.FutureTask.run(FutureTask.java:237)
System.err﹕ at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
System.err﹕ at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
System.err﹕ at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
System.err﹕ at java.lang.Thread.run(Thread.java:841)
System.err﹕ Caused by: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x5e522ba8: Failure in SSL library, usually a protocol error
System.err﹕ error:1407743E:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert inappropriate fallback (external/openssl/ssl/s23_clnt.c:744 0x5e5967e8:0x00000000)
System.err﹕ at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
System.err﹕ at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:406)
System.err﹕ ... 16 more 

我的代码:

我的代码基于此:https://developer.android.com/training/articles/security-ssl.html

//Get Cert
try {
   InputStream CertInputStream = a_sContext.getResources().openRawResource(R.raw.server);

   //Read Cert
   CertificateFactory CertFactory = CertificateFactory.getInstance("X.509");
   Certificate Cert = CertFactory.generateCertificate(CertInputStream);
   String Result = "Ca=" + ((X509Certificate) Cert).getSubjectDN();
   Log.d("test", Result); //This Returns correct Cert information

   //Create a keystore
   KeyStore MyKeyStore = KeyStore.getInstance(KeyStore.getDefaultType());
   MyKeyStore.load(null, null);
   MyKeyStore.setCertificateEntry("ca", Cert);

   //Create a TrustManager
   TrustManagerFactory TMF = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
   TMF.init(MyKeyStore);

   //Create a SSLContext
   m_pSSLContext = SSLContext.getInstance("TLS");
   m_pSSLContext.init(null, TMF.getTrustManagers(), null);
   HttpsURLConnection.setDefaultSSLSocketFactory(m_pSSLContext.getSocketFactory());

   //Try and connect to the website
   URL MyURL = new URL(m_sSecureHttp + m_sWebsite + m_sTestPath);
   con = (HttpsURLConnection) MyURL.openConnection();
   con.connect();
   Result = new String();
   BufferedReader reader = new BufferedReader(new InputStreamReader(con.getInputStream()));;
   while((Line = reader.readLine())!= null) {
        Result += Line;
   }
}
catch (Exception e) { e.printStackTrace(); }

服务器端:

我生成了以下证书:http://robsnotebook.com/xampp-ssl-encrypt-passwords

这似乎有效,因为我的本地计算机和 android 浏览器可以访问它。此外,在 XAMPP 的 ssl_request.log 中,我可以从本地计算机或通过我的 android 浏览器查看我的所有连接尝试,但它甚至没有提到来自我的应用程序的请求。 access.log 也是如此。

我正在 Android 4.4.2 上测试 android 应用程序

我的实际问题

有人知道如何解决 SSL 握手错误吗?任何提示都是有用的!我尝试了很多可以在 google 上找到的东西,但到目前为止都没有。

【问题讨论】:

标签: android apache ssl https xampp


【解决方案1】:

Android 4.4.2 版本存在一个已知错误,该错误是在使用 TLSv1.x 协议访问 HTTPS 时引起的。由于不支持 TLS,握手失败,因此 HttpsURLConnection 回退到 SSLv3 协议,导致握手时发生错误。我没有找到不涉及重新实现 HttpsURLConnection 的 TrustManagers 以防止错误或连接不安全的解决方法。

这就是我所做的:

为您的 SSLContext 提供自定义信任管理器:

// Trust manager that recognizes you acceptance criteria, that being ignoring handshake errors
        ResourceTrustManager trustManager = new ResourceTrustManager(sslKeyStores);
        TrustManager[] trustManagers = {trustManager};
        // use: org.apache.http.conn.ssl.AllowAllHostnameVerifier, this can be optional depending on your case.
        AllowAllHostnameVerifier resourceHostNameVerifier = new AllowAllHostnameVerifier(); 

        // Install the trust manager and host name verifier
        try {
            SSLContext sc = SSLContext.getInstance("TLS");
            sc.init(null, trustManagers, new java.security.SecureRandom());
            HttpsURLConnection
                    .setDefaultSSLSocketFactory(sc.getSocketFactory());
            HttpsURLConnection.setDefaultHostnameVerifier(resourceHostNameVerifier);
        } catch (Exception e) {
            Log.e(TAG, "Invalid algorithm used while setting trust store:" +e.getMessage());
            throw e;
        }

要实现您的信任管理器,只需覆盖:

  • public void checkClientTrusted
  • public void checkServerTrusted

我的使用本地密钥库来尝试授权证书:

public class ResourceTrustManager implements X509TrustManager {

private static final String TAG = ResourceTrustManager.class.getName();
protected ArrayList<X509TrustManager> x509TrustManagers = new ArrayList<X509TrustManager>();

public ResourceTrustManager(Collection<KeyStore> additionalkeyStores) {
    final List<TrustManagerFactory> factories = new ArrayList<TrustManagerFactory>();

    try {
        /**
         * Consolidates central and aditional keystore to be used as trust managers
         */
        final TrustManagerFactory original = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        original.init((KeyStore) null);
        factories.add(original);

        if(additionalkeyStores != null ) {
            for (KeyStore keyStore : additionalkeyStores) {
                final TrustManagerFactory additionalCerts = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
                additionalCerts.init(keyStore);
                factories.add(additionalCerts);
            }
        }

    } catch (Exception e) {
        throw new RuntimeException(e);
    }

    for (TrustManagerFactory tmf : factories) {
        for (TrustManager tm : tmf.getTrustManagers()) {
            if (tm instanceof X509TrustManager) {
                x509TrustManagers.add((X509TrustManager) tm);
            }
        }
    }

    ResourceAssert.hasLength(x509TrustManagers, "Could not initialize with no trust managers");

}

public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
    // The default Trustmanager with default keystore
    final X509TrustManager defaultX509TrustManager = x509TrustManagers.get(0);
    defaultX509TrustManager.checkClientTrusted(chain, authType);

}

public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
    for( X509TrustManager tm : x509TrustManagers ) {
        try {
            tm.checkServerTrusted(chain,authType);
            return;
        } catch( CertificateException e ) {
            StringBuilder issuers = new StringBuilder();

            if(chain != null){
                for(X509Certificate cert :chain){
                    issuers.append( " " +cert.getIssuerDN().getName() );
                }
            }

            Log.e(TAG, "Untrusted host, connection is not secure "+ issuers + "\n\n" + e.getMessage());
        }
    }

}

public X509Certificate[] getAcceptedIssuers() {
    final ArrayList<X509Certificate> list = new ArrayList<X509Certificate>();

    for( X509TrustManager tm : x509TrustManagers ) {
        list.addAll(Arrays.asList(tm.getAcceptedIssuers()));
    }

    return list.toArray(new X509Certificate[list.size()]);
}


}

这一点也不优雅,但可以完成工作。

【讨论】:

    猜你喜欢
    • 2014-03-08
    • 2018-11-13
    • 2017-06-02
    • 2014-10-26
    • 1970-01-01
    • 2015-07-13
    • 2015-03-09
    • 2012-12-22
    • 2018-10-19
    相关资源
    最近更新 更多