从安全扫描程序的结果来看,我需要限制应用程序信任的证书颁发机构。
扫描结果指出webView.loadUrl("https://example.com/page");
处的行。我看到如何创建一个使用我的TrustManager的SslSocketFactory,但我没有在WebView中看到允许我设置它的API。
https://developer.android.com/training/articles/security-ssl.html#UnknownCa
有哪些可能的方法来实现这一目标?
答案 0 :(得分:3)
我认为WebViewClient
' onReceivedSslError
方法将是一个很好的切入点。
首先,请遵循https://developer.android.com/training/articles/security-ssl.html#UnknownCa中完全相同的代码段来准备TrustManager。
TrustManagerFactory tmf = null;
private void initTrustStore() throws
java.security.cert.CertificateException, FileNotFoundException,
IOException, KeyStoreException, NoSuchAlgorithmException {
// Create a KeyStore containing our trusted CAs
String keyStoreType = KeyStore.getDefaultType();
KeyStore trustedKeyStore = KeyStore.getInstance(keyStoreType);
trustedKeyStore.load(null, null);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream caInput = new BufferedInputStream(
getResources().getAssets().open("ca.crt"));
Certificate ca;
try {
ca = cf.generateCertificate(caInput);
Log.d(TAG, "ca-root DN=" + ((X509Certificate) ca).getSubjectDN());
}
finally {
caInput.close();
}
trustedKeyStore.setCertificateEntry("ca", ca);
// Create a TrustManager that trusts the CAs in our KeyStore
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(trustedKeyStore);
}
然后,扩展自定义WebViewClient类,从https://stackoverflow.com/a/6379434/1099884
检查代码段private class CheckServerTrustedWebViewClient extends WebViewClient{
public void onReceivedSslError(WebView view, final SslErrorHandler handler, SslError error) {
Log.d(TAG, "onReceivedSslError");
boolean passVerify = false;
if(error.getPrimaryError() == SslError.SSL_UNTRUSTED){
SslCertificate cert = error.getCertificate();
String subjectDN = cert.getIssuedTo().getDName();
Log.d(TAG, "subjectDN: "+subjectDN);
try{
Field f = cert.getClass().getDeclaredField("mX509Certificate");
f.setAccessible(true);
X509Certificate x509 = (X509Certificate)f.get(cert);
X509Certificate[] chain = {x509};
for (TrustManager trustManager: tmf.getTrustManagers()) {
if (trustManager instanceof X509TrustManager) {
X509TrustManager x509TrustManager = (X509TrustManager)trustManager;
try{
x509TrustManager.checkServerTrusted(chain, "generic");
passVerify = true;break;
}catch(Exception e){
Log.e(TAG, "verify trustManager failed", e);
passVerify = false;
}
}
}
Log.d(TAG, "passVerify: "+passVerify);
}catch(Exception e){
Log.e(TAG, "verify cert fail", e);
}
}
if(passVerify == true)handler.proceed();
else handler.cancel();
}
}
最后,将CheckServerTrustedWebViewClient
设置为WebView
webView.setWebViewClient(new CheckServerTrustedWebViewClient());
然而,有一个问题。准备好的CA证书是服务器1的正确签名(中间CA非根CA)。仅提供根CA证书将不起作用。不是TrustManager可以在运行时下载服务器证书链吗?有什么建议吗?