我们如何在Android上的HttpClient 4.4+中启用SNI?
问题描述:
我想解决在现代版本的Android上使用主要HTTP堆栈的SNI的食谱。这包括Apache独立的HttpClient库(不是版本,它已经销毁到Android本身,它已经不复存在了)。我们如何在Android上的HttpClient 4.4+中启用SNI?
看来最近的HttpClient版本不支持SNI开箱即用。当我使用'cz.msebera.android:httpclient:4.4.1.1'
神器,我得到:
javax.net.ssl.SSLPeerUnverifiedException: Host name '...' does not match the certificate subject provided by the peer (CN=...)
at cz.msebera.android.httpclient.conn.ssl.SSLConnectionSocketFactory.verifyHostname(SSLConnectionSocketFactory.java:466)
at cz.msebera.android.httpclient.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:395)
(与...
删节主机名)
This HttpClient issue有一些代码,声称解决这一问题。但是,目前尚不清楚如何使用它。 This Stack Overflow answer有助于实现。然而,这反过来与一个等效的异常崩溃:
javax.net.ssl.SSLPeerUnverifiedException: Host name '' does not match the certificate subject provided by the peer (CN=...)
at cz.msebera.android.httpclient.conn.ssl.SSLConnectionSocketFactory.verifyHostname(SSLConnectionSocketFactory.java:466)
at cz.msebera.android.httpclient.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:395)
这并不让我感到意外。建议的解决方法(用空字符串替换真实的主机名)让我觉得很奇怪。
This Stack Overflow question-and-answer基本上说“使用Java 1.7”,这不是Android的可行选项。
那么,有没有人制定了一个配方,以启用与Android兼容的HttpClient 4.4+环境的SNI?
答
尝试使用SSLConnectionSocketFactory的这个版本,而不是Marek Sebera的HttpClient fork。它包含这个Andriod特定位的代码。上次我使用官方的Apache端口HttpClient 4.3测试SNI时,它工作得很好。
// Android specific code to enable SNI
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Enabling SNI for " + target);
}
try {
Method method = sslsock.getClass().getMethod("setHostname", String.class);
method.invoke(sslsock, target);
} catch (Exception ex) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "SNI configuration failed", ex);
}
}
}
// End of Android specific code
谢谢!不幸的是,这是从4.3开始的,它取决于不存在的东西。然而,这*表明我可以在哪里介绍'setHostname'反射破解,我正在使用'HttpURLConnection'成功地使用(任何反射破解代表“成功”)。我已经有一个自定义的'createLayeredSocket()'''SSLConnectionSocketFactory'的自定义子类。我不会链接到超类实现,而是尝试克隆那些代码并在反射黑客中混合。 – CommonsWare
我清除了克隆['SSLConnectionSocketFactory'的4.4.1版](http://svn.apache.org/repos/asf/httpcomponents/httpclient/tags/4.4.1/httpclient/src/main/java/org /apache/http/conn/ssl/SSLConnectionSocketFactory.java)并将您的答案中的代码引入'createLayeredSocket()'中,该链接位于与链接到的'4.3.5.1'版本相同的位置(在'prepareSocket()'之后) ,在'startHandshake()'之前)。这似乎工作。我的目标是最终把这个卷入图书馆。再次感谢! – CommonsWare
我很高兴,帮助。请考虑向Marek报告此问题,并要求他将修补程序整合到他的叉子中。 – oleg