我有一个ListView,其中包含一些内容(TextViews,ImageView ...)。我使用Nostra的UIL来加载项目中的图像,但其中一些无法加载。当我打电话给Log.v(String.valueOf(failReason.getCause());
时,这就是我得到的:
11-16 23:52:20.447: V/javax.net.ssl.SSLHandshakeException: Handshake failed(17467): failz
11-16 23:52:20.657: V/NativeCrypto(17467): SSL handshake aborted: ssl=0x15fd758: Failure in SSL library, usually a protocol error
11-16 23:52:20.657: V/NativeCrypto(17467): error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure (external/openssl/ssl/s23_clnt.c:762 0x4c2ed485:0x00000000)
11-16 23:52:21.207: V/NativeCrypto(17467): SSL handshake aborted: ssl=0x1562468: Failure in SSL library, usually a protocol error
11-16 23:52:21.207: V/NativeCrypto(17467): error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure (external/openssl/ssl/s23_clnt.c:762 0x4c2ed485:0x00000000)
你知道吗,为什么会出现这个问题或者我该如何解决?
这是一个没有加载的示例图像:
http://bigparty.cz/photos/headlinefoto/13.jpg
(我可以附加一个包含整个错误的日志 - UIL 自动放入日志的错误)
答案 0 :(得分:9)
如果我是对的,您必须创建证书,签名并将其包含在您的应用中。或者更改服务器配置(further information here)。
否则,您可以信任您的应用中的每次握手。这不是最好的方法,但在实施过程中非常有用。
在项目中包含此课程
public class SSLCertificateHandler {
protected static final String TAG = "NukeSSLCerts";
/**
* Enables https connections
*/
public static void nuke() {
try {
TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
X509Certificate[] myTrustedAnchors = new X509Certificate[0];
return myTrustedAnchors;
}
@Override
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
@Override
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
} };
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
});
} catch (Exception e) {
}
}
}
扩展您的Application
,并致电“核心”'功能在onCreate
public class YOURApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
//...
// trust all SSL -> HTTPS connection
SSLCertificateHandler.nuke();
}
我在SO中找到了这段代码,但目前无法找到该链接....
答案 1 :(得分:2)
您可能在服务器端缺少中间CA证书。
试试这个
大多数公共CA都不直接签署服务器证书。相反,他们使用他们的主CA证书(称为根CA)来签署中间CA.他们这样做是为了使根CA可以离线存储以降低危害的风险。但是,像Android这样的操作系统通常只直接信任根CA,这在由中间CA签名的服务器和知道根CA的证书验证者之间留下了很小的信任差距。要解决此问题,服务器在SSL握手期间不会向客户端发送它的证书,而是从服务器CA通过任何到达受信任根CA所需的中间件的证书链。
要查看实际情况,请参阅openssl s_client命令查看的mail.google.com证书链:
证书链 0 s:/ C = US / ST =加州/ L =山景/ O = Google Inc / CN = mail.google.com i:/ C = ZA / O = Thawte Consulting(Pty)Ltd./CN=Thawte SGC CA. 1 s:/ C = ZA / O = Thawte Consulting(Pty)Ltd./CN=Thawte SGC CA
这表明服务器发送由Thawte SGC CA(一个中间CA)发布的mail.google.com证书,以及由Verisign CA颁发的Thawte SGC CA的第二个证书,该证书是主要CA.这是受到Android信任的。
但是,将服务器配置为不包含必要的中间CA并不罕见。例如,这是一个服务器,可能会导致Android浏览器中的错误和Android应用中的异常:
证书链 0 s:/ C = US / ST =哥伦比亚特区/ L =华盛顿/ O =美国。国土安全部/ OU =美国公民及移民服务局/ OU =使用条款:www.verisign.com/rpa(c)05 / CN = egov.uscis.gov
这里有趣的是,在大多数桌面浏览器中访问此服务器不会导致像完全未知的CA或自签名服务器证书那样的错误。这是因为大多数桌面浏览器会随着时间的推移缓存可信中间CA.一旦浏览器访问并从一个站点了解到中间CA,下次就不需要在证书链中包含中间CA.
有些网站会故意为用于提供资源的辅助Web服务器执行此操作。例如,他们的主HTML页面可能由具有完整证书链的服务器提供服务,但是服务器用于资源(如图像,CSS或JavaScript)不包括CA,可能是为了节省带宽。不幸的是,有时这些服务器可能会提供您尝试从Android应用程序调用的Web服务,这不是宽容的。
有两种方法可以解决这个问题:
配置服务器以在服务器链中包含中间CA.大多数CA提供有关如何为所有常见Web服务器执行此操作的文档。如果您需要网站至少通过Android 4.2使用默认Android浏览器,这是唯一的方法。 或者,将中间CA视为任何其他未知CA,并创建一个TrustManager直接信任它,如前两节所述。
答案 2 :(得分:2)
正如龙龙所说,所有证书都不是最好的方法。实际上,它在生产环境中是一种非常糟糕的方法,因为它基本上使SSL的效果无效并使您对Man-in-the-middle attacks感到尊敬。
问题归结为POODLE SSL3 bug,这使得一些(大多数?)服务提供商禁用了他们的SSLv3支持。这对Android开发人员来说是个坏消息,因为HttpConnection默认为Build.VERSION.SDK_INT> = 9&&amp ;;中的SSLv3。 Build.VERSION.SDK_INT< = 20。
Android issue tracker中存在一个问题,其中包含更多信息,解决方案包括提供自定义SSLFactory,拒绝将SSLv3设置为唯一的回退协议,以下是该问题的代码。我不赞成这个解决方案,但它是我们目前在Lollipop之前所有版本使用的。
/**
* An {@link javax.net.ssl.SSLSocket} that doesn't allow {@code SSLv3} only connections
* <p>fixes https://github.com/koush/ion/issues/386</p>
*/
private static class NoSSLv3SSLSocket extends DelegateSSLSocket {
private NoSSLv3SSLSocket(SSLSocket delegate) {
super(delegate);
String canonicalName = delegate.getClass().getCanonicalName();
if (!canonicalName.equals("org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl")){
// try replicate the code from HttpConnection.setupSecureSocket()
try {
Method msetUseSessionTickets = delegate.getClass().getMethod("setUseSessionTickets", boolean.class);
if (null != msetUseSessionTickets) {
msetUseSessionTickets.invoke(delegate, true);
}
} catch (NoSuchMethodException ignored) {
} catch (InvocationTargetException ignored) {
} catch (IllegalAccessException ignored) {
}
}
}
@Override
public void setEnabledProtocols(String[] protocols) {
if (protocols != null && protocols.length == 1 && "SSLv3".equals(protocols[0])) {
// no way jose
// see issue https://code.google.com/p/android/issues/detail?id=78187
List<String> enabledProtocols = new ArrayList<String>(Arrays.asList(delegate.getEnabledProtocols()));
if (enabledProtocols.size() > 1) {
enabledProtocols.remove("SSLv3");
} else {
LogManager.getLogger().w("SSL stuck with protocol available for " + String.valueOf(enabledProtocols));
}
protocols = enabledProtocols.toArray(new String[enabledProtocols.size()]);
}
super.setEnabledProtocols(protocols);
}
}
/**
* {@link javax.net.ssl.SSLSocketFactory} that doesn't allow {@code SSLv3} only connections
*/
private static class NoSSLv3Factory extends SSLSocketFactory {
private final SSLSocketFactory delegate;
private NoSSLv3Factory() {
this.delegate = HttpsURLConnection.getDefaultSSLSocketFactory();
}
@Override
public String[] getDefaultCipherSuites() {
return delegate.getDefaultCipherSuites();
}
@Override
public String[] getSupportedCipherSuites() {
return delegate.getSupportedCipherSuites();
}
private static Socket makeSocketSafe(Socket socket) {
if (socket instanceof SSLSocket) {
socket = new NoSSLv3SSLSocket((SSLSocket) socket);
}
return socket;
}
@Override
public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
return makeSocketSafe(delegate.createSocket(s, host, port, autoClose));
}
@Override
public Socket createSocket(String host, int port) throws IOException {
return makeSocketSafe(delegate.createSocket(host, port));
}
@Override
public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException {
return makeSocketSafe(delegate.createSocket(host, port, localHost, localPort));
}
@Override
public Socket createSocket(InetAddress host, int port) throws IOException {
return makeSocketSafe(delegate.createSocket(host, port));
}
@Override
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
return makeSocketSafe(delegate.createSocket(address, port, localAddress, localPort));
}
}
static {
HttpsURLConnection.setDefaultSSLSocketFactory(new NoSSLv3Factory());
}