在Android中使用SSL/TLS,通过校验服务器端来实现安全通信。(这里指单向SSL/TLS, 与之对应的是双向SSL校验,双向SSL 指的是同时校验客户端和服务端证书), 开发者可以自由实现SSL 通信,然而很多开发者不能恰当的使用SSL协议,导致用户的敏感数据在传输过程中泄露。
漏洞分类:忽略SSL证书校验、忽略域名校验。
在自定义实现X509TrustManager时,checkServerTrusted中没有检查证书是否可信,导致通信过程中可能存在中间人攻击,造成敏感数据劫持危害。由于客户端没有校验服务端的证书,因此攻击者就能与通讯的两端分别创建独立的联系,并交换其所收到的数据,使通讯的两端认为他们正在通过一个私密的连接与对方直接对话,但事实上整个会话都被攻击者完全控制。在中间人攻击中,攻击者可以拦截通讯双方的通话并插入新的内容。
public class MyX509TrustManager implements X509TrustManager {
// 检查客户端证书
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
// 检查服务器端证书
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
// 返回受信任的X509证书数组
public X509Certificate[] getAcceptedIssuers() {
return null;
}
}
在重写WebViewClient的onReceivedSslError方法时,调用proceed忽略证书验证错误信息继续加载页面,导致通信过程中可能存在中间人攻击,造成敏感数据劫持危害。
mywebview.setWebViewClient(new WebviewClient(){
@Override
public void onReceivedError(WebView view,int errorCode,String description,String falingUrl){
// TODO Auto generated method stub
super.onReceivedError(view,errorCode,description,fallingUrl) ;
}
@Override
public void onReceivedSslError(WebView view,SslErrorHandler handler,SslError error)
// T0D0 Auto-generated method stub
handler.proceed( );
};
});
防护:
建议自定义实现X509TrustManager时,checkServerTrusted中对服务器信息进行严格校验。
针对自定义TrustManager,检查checkServerTrusted()函数是否为空实现。
建议不要重写TrustManager 和HostnameVerifier,使用系统默认的。
在重写WebViewClient的onReceivedSslError方法时,避免调用proceed忽略证书验证。
2. 忽略域名校验
在自定义实现HostnameVerifier时,没有在verify中进行严格证书校验,导致通信过程中可能存在中间人攻击,造成敏感数据劫持危害。
HostnameVerifier hv = new HostnameVerifier (){
@Override
public boolean verify(String hostname,SSLSession session){
return true;
}
};
在setHostnameVerifier方法中使用ALLOW_ALL_HOSTNAME _VERIFIER,信任所有Hostname,导致通信过程中可能存在中间人攻击,造成敏感数据劫持危害。
private HttpClient getNewHttpClient() {
try {
KeyStore trustStore = KeyStore.getInstance(KeyStore
.getDefaultType());
trustStore.load(null, null);
SSLSocketFactory sf = new SSLSocketFactory(trustStore);
sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
HttpParams params = new BasicHttpParams();
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("http", PlainSocketFactory
.getSocketFactory(), 80));
registry.register(new Scheme("https", sf, 443));
ClientConnectionManager ccm = new ThreadSafeClientConnManager(
params, registry);
return new DefaultHttpClient(ccm, params);
} catch (Exception e) {
return new DefaultHttpClient();
}
}
防护:
在自定义实现HostnameVerifier时,在verify中对Hostname进行严格校验。
建议setHostnameVerifier方法中使用STRICT_HOSTNAME VERIFIER进行严格证书校验,避免使用ALLOW ALL.HOSTNAME _VERIFIER.