我是任何网络相关编程的新手,所以我知道我正在深入研究,但我在我的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握手错误?任何提示都很有用!我尝试了很多我可以在谷歌上找到的东西,但到目前为止都没有。
答案 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;
}
要实现您的信任管理器,只需覆盖:
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()]);
}
}
这根本不优雅,但可以完成工作。