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

标签 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 浏览器看到我所有的连接尝试,但它甚至一次都没有提到来 self 的应用程序的请求。这与 access.log 相同。

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

我的实际问题

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

最佳答案

Android 4.4.2 版本中存在一个已知错误,该错误是在使用 TLSv1.x 协议(protocol)访问 HTTPS 时引起的。握手失败,因为不支持 TLS,因此 HttpsURLConnection 回退到 SSLv3 协议(protocol),导致握手时发生错误。我还没有找到不涉及重新实现 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

我的使用本地 keystore 来尝试授权证书:

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


}

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

关于连接到我的本地 XAMPP 托管网站时 SSL 库中的 Android 失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31501676/

相关文章:

C# 应用程序无法建立 SSL/TLS 连接

android - Firebase limitToLast 查询

java - 数组中多个字符串的位置

android - 单击 flutter 中的底部按钮时在半屏中显示选项卡

java - 在 Android 中使用 SharedPreferences 存储数据

regex - 如何将 *.htm *,htm *,html 重定向到 .htaccess 中的 *.html

在 Glassfish Server 上导入 SSL 证书,但浏览器显示 https URL 错误

php - AWS Elasticbeanstalk 单实例强制 SSL

ruby-on-rails - 无法访问日志文件。请确保path/to/Production.log存在并且可写

java - maven : UnknownHostException: repo. maven.apache.org