连接到我的本地XAMPP托管网站时,SSL库中出现Android故障

连接到我的本地XAMPP托管网站时,SSL库中出现Android故障,android,apache,ssl,https,xampp,Android,Apache,Ssl,Https,Xampp,我对任何与网络相关的编程都是新手,所以我知道我正在深入研究,但我在android HttpsURLConnection和本地XAMPP托管网站之间成功地进行SSL握手时遇到了问题,而不仅仅是一个返回Hello World的php脚本!首先,我可以从我的计算机(主机)和android手机的浏览器(https)加载此页面 问题: 当我尝试通过HttpsURLConnection将应用程序与服务器连接时,我遇到以下错误: System.err﹕ javax.net.ssl.SSLHandshakeEx

我对任何与网络相关的编程都是新手,所以我知道我正在深入研究,但我在android HttpsURLConnection和本地XAMPP托管网站之间成功地进行SSL握手时遇到了问题,而不仅仅是一个返回Hello World的php脚本!首先,我可以从我的计算机(主机)和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 
我的代码:

我的代码基于以下内容:

服务器端:

我生成了以下证书:

自从我的本地电脑和安卓浏览器可以访问它以来,这似乎起到了作用。此外,在XAMPP的ssl_request.log中,我可以从本地计算机或android浏览器看到所有连接尝试,但它甚至一次都没有提到来自应用程序的请求。这与access.log相同

我正在安卓4.4.2上测试安卓应用程序

我的实际问题


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

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

这就是我所做的:

将自定义信任管理器提供给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;
        }
要实施信任管理器,只需覆盖:

  • 公共无效checkClientTrusted
  • 公共无效检查服务器受信任
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()]);
}


}
公共类ResourceTrustManager实现X509TrustManager{
私有静态最终字符串标记=ResourceTrustManager.class.getName();
受保护的ArrayList X509TrustManager=新ArrayList();
公共资源信任管理器(集合附加密钥库){
最终列表工厂=新的ArrayList();
试一试{
/**
*整合用作信托管理器的中央密钥库和传统密钥库
*/
最终TrustManagerFactory original=TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
init((密钥库)null);
工厂。添加(原件);
if(additionalkeyStores!=null){
用于(密钥库密钥库:附加密钥库){
final TrustManagerFactory additionalCerts=TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
附加证书初始化(密钥库);
工厂。添加(附加证书);
}
}
}捕获(例外e){
抛出新的运行时异常(e);
}
对于(TrustManagerFactory tmf:工厂){
for(TrustManager tm:tmf.getTrustManagers()){
if(X509TrustManager的tm实例){
x509TrustManagers.add((X509TrustManager)tm);
}
}
}
ResourceAssert.hasLength(X509TrustManager,“无法在没有信任管理器的情况下初始化”);
}
public void checkClientTrusted(X509Certificate[]链,字符串authType)引发CertificateException{
//具有默认密钥库的默认Trustmanager
最终X509TrustManager默认X509TrustManager=X509TrustManager.get(0);
defaultX509TrustManager.checkClientTrusted(链,authType);
}
public void checkServerTrusted(X509Certificate[]链,字符串authType)引发CertificateException{
适用于(X509TrustManager tm:X509TrustManager){
试一试{
tm.checkServerTrusted(链,authType);
返回;
}捕获(证书例外e){
StringBuilder发行人=新StringBuilder();
如果(链!=null){
对于(X509证书证书:链){
append(“+cert.getIssuerDN().getName());
}
}
Log.e(标记“不受信任的主机,连接不安全”+颁发者+“\n\n”+e.getMessage());
}
}
}
公共X509证书[]getAcceptedIssuers(){
最终ArrayList=新ArrayList();
适用于(X509TrustManager tm:X509TrustManager){
addAll(Arrays.asList(tm.getAcceptedIssuers());
}
return list.toArray(新的X509Certificate[list.size()]);
}
}

这一点也不优雅,但完成了任务。

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

这就是我所做的:

将自定义信任管理器提供给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;
        }
要实施信任管理器,只需覆盖:

  • 公共无效checkClientTrusted
  • 公共无效检查服务器受信任
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()]);
}


}
公共类ResourceTrustManager实现X509TrustManager{
私有静态最终字符串标记=ResourceTrustManager.class.getName();
受保护的ArrayList X509TrustManager=新ArrayList();
公共资源信任管理器(集合附加密钥库){
最终列表工厂=新的ArrayList();
试一试{
/**
*整合用作信托管理器的中央密钥库和传统密钥库