把服务器的证书放置在 assert 文件夹,当出现 ssl error 的时候进行读取,然后与服务器校验,校验通过了就加载该网页。校验不通过,不打开网页,进行安全提醒。
public class WebviewClient3 extends WebViewClient { private Context context; public WebviewClient3(Context context) { this.context = context; } @Override public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) { test12306(handler, view.getUrl()); } // 以 12306 的证书为例,因为 12306 的证书是自签名的 private void test12306(final SslErrorHandler handler, String url) { OkHttpClient.Builder builder; try { builder = setCertificates(new OkHttpClient.Builder(), context.getAssets().open(MainActivity.cer_protal_root)); } catch (IOException e) { builder = new OkHttpClient.Builder(); } Request request = new Request.Builder().url(url) .build(); builder.build().newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { Log.e("12306 error", e.getMessage()); handler.cancel(); } @Override public void onResponse(Call call, Response response) throws IOException { Log.e("12306 ", response.body().string()); handler.proceed(); } }); } private OkHttpClient.Builder setCertificates(OkHttpClient.Builder client, InputStream... certificates) { try { CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); KeyStore keyStore = KeyStore.getInstance("PKCS12", "BC"); keyStore.load(null); int index = 0; for (InputStream certificate : certificates) { String certificateAlias = Integer.toString(index++); keyStore.setCertificateEntry(certificateAlias, certificateFactory.generateCertificate(certificate)); try { if (certificate != null) certificate.close(); } catch (IOException e) { } } SSLContext sslContext = SSLContext.getInstance("TLS"); TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); trustManagerFactory.init(keyStore); sslContext.init(null, trustManagerFactory.getTrustManagers(), new SecureRandom()); SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory(); X509TrustManager trustManager = Platform.get().trustManager(sslSocketFactory); client.sslSocketFactory(sslSocketFactory, trustManager); } catch (Exception e) { e.printStackTrace(); } return client; } }
以上代码可以针对规范的自签名证书进行校验了。但是呢,我们的证书不规范,会出现 Hostname xxx not verified 的情况。这种情况需要对 Hostname 进行校验。需要在 client 上添加如下代码
client.hostnameVerifier(new HostnameVerifier() { @Override public boolean verify(String hostname, SSLSession session) { String peerHost = session.getPeerHost();//服务器返回的域名 try { X509Certificate[] peerCertificates = (X509Certificate[]) session.getPeerCertificates(); for (X509Certificate c : peerCertificates) { X500Principal subjectX500Principal = c.getSubjectX500Principal(); String name = new X500p(subjectX500Principal).getName(); String[] split = name.split(","); for (String s : split) { if (s.startsWith("CN")) { if (s.contains(hostname) && s.contains(peerHost)) { return true; } } } } } catch (SSLPeerUnverifiedException e) { e.printStackTrace(); } return false; } });
原文链接:https://www.cnblogs.com/liyiran/p/7011317.html
原创文章,作者:优速盾-小U,如若转载,请注明出处:https://www.cdnb.net/bbs/archives/17448