连接到我的本地XAMPP托管网站时,SSL库中的Android失败

时间:2015-07-19 13:23:12

标签: android apache ssl https xampp

我是任何网络相关编程的新手,所以我知道我正在深入研究,但我在我的Android HttpsURLConnection和我的本地XAMPP托管网站之间获得成功的SSL握手问题,而不仅仅是一个PHP脚本返回Hello World!我先说我可以从我的电脑(主机)和我的Android手机浏览器( 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握手错误?任何提示都很有用!我尝试了很多我可以在谷歌上找到的东西,但到目前为止都没有。

1 个答案:

答案 0 :(得分:0)

使用 TLSv1.x 协议访问HTTPS时,版本 Android 4.4.2 存在已知错误。握手失败,因为不支持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

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

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()]);
}


}

这根本不优雅,但可以完成工作。