Доверительный центр сертификации в WebView loadUrl()
В результате сканирования программы безопасности мне нужно ограничить центры сертификации, которым доверяет приложение.
Результат сканирования указывает на строку в webView.loadUrl("https://example.com/page");
, Я вижу, как я могу создать SslSocketFactory, который использует мой TrustManager, но я не вижу API в WebView, который позволил бы мне установить это.
https://developer.android.com/training/articles/security-ssl.html
Каковы возможные пути достижения этого?
2 ответа
Я думаю WebViewClient
"s onReceivedSslError
Метод будет хорошей отправной точкой.
Прежде всего, следуйте тому же фрагменту из https://developer.android.com/training/articles/security-ssl.html чтобы подготовить 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, проверяя фрагмент из /questions/44556059/proverka-sertifikatov-x509-s-ispolzovaniem-java-apis/44556068#44556068
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 является точным знаком сервера (промежуточный CA НЕ является корневым CA). Только предоставить сертификат корневого CA не будет работать. Разве TrustManager не может загружать цепочку сертификатов сервера во время выполнения? Любое предложение?
Документ , похоже , обновлен:
К счастью, вы можете научить свое приложение доверять пользовательским центрам сертификации, настроив конфигурацию сетевой безопасности вашего приложения без необходимости изменять код внутри вашего приложения.