zoukankan      html  css  js  c++  java
  • android获取https证书

    最近碰到一个问题, 有朋友问android这边能不能拿到服务器下发的证书,意思就是   自签名证书的https接口,在请求的时候,也没有添加自签名证书进信任列表,直接去发https请求,按照正常https步骤去理解,服务器会返回一个证书,这个证书由于客户端没有添加进信任列表,会导致https请求失败,提示没有找到信任的证书。  朋友疑问: 在服务器返回证书的时候,能不能强行信任呢? 

    针对这个问题, 我在这边做了测试:

    1,由ca签发的ssl证书,部署一个服务

      不设置请求的SSLSocketFactory,直接进行https请求

        验证结果:ok

    2,自签名的ssl证书,部署一个服务

     不设置请求的SSLSocketFactory,直接进行https请求

        验证结果:error,报错信息   java.security.cert.CertPathValidatorException: Trust anchor for certification path not found,大体意思是没有找打信任的证书,也就是说这个证书没有被当前的请求对象所信任。

    看报错信息是android系统已经封装好的证书校验规则。

    但是如果不想本地预埋自签名证书,也不想让后台暴露证书下载的接口,该怎么办呢?

    我这边提供一个比较简陋的方法,通过webview访问目标https地址,通过webview的onReceivedSslError方法,拿到SslError中的SslCertificate,然后再根据SslCertificate中的saveState方法获取Bundle,从bundle中拿到"x509-certificate"的字节数组,作为字节流读取流,通过通用的httpsutils,设置请求对象的sslsocketfactory。

    代码如下:

    package com.example.ajaxhttpsdemo;
    
    import android.content.Context;
    import android.net.http.SslCertificate;
    import android.net.http.SslError;
    import android.os.Bundle;
    import android.os.Handler;
    import android.util.Log;
    import android.webkit.SslErrorHandler;
    import android.webkit.WebSettings;
    import android.webkit.WebView;
    import android.webkit.WebViewClient;
    
    import java.io.ByteArrayInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.security.KeyManagementException;
    import java.security.KeyStore;
    import java.security.KeyStoreException;
    import java.security.NoSuchAlgorithmException;
    import java.security.cert.CertificateException;
    import java.security.cert.CertificateFactory;
    import java.security.cert.X509Certificate;
    
    import javax.net.ssl.KeyManager;
    import javax.net.ssl.KeyManagerFactory;
    import javax.net.ssl.SSLContext;
    import javax.net.ssl.SSLException;
    import javax.net.ssl.SSLSocketFactory;
    import javax.net.ssl.TrustManager;
    import javax.net.ssl.TrustManagerFactory;
    import javax.net.ssl.X509TrustManager;
    
    public class HttpsGetSSLSocketFactory {
        private static SslCertificate sslCertificate;
        public static class SSLParams {
            public SSLSocketFactory sSLSocketFactory;
            public X509TrustManager trustManager;
        }
    
        public interface Callback{
            void onSuccess(SSLParams sslParams);
            void onError(Exception e);
        }
    
        public static class MySSLException extends Exception{
            public MySSLException(String str) {
                super(str);
            }
        }
    
        public static void getSslSocketFactoryOnMainThread(Context context, String httpsUrl, final Callback callback){
            WebView webView = new WebView(context);
            webView.setWebViewClient(new WebViewClient(){
                @Override
                public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
                    sslCertificate = error.getCertificate();
                    handler.proceed();
                    if (sslCertificate!=null){
                        Bundle bundle = SslCertificate.saveState(sslCertificate);
                        byte[] byteArray = bundle.getByteArray("x509-certificate");//从bundle中拿出写入的x509证书
    //                    byte[] byteArray = "123456".getBytes();//测试错误证书
                       if (byteArray!=null && byteArray.length>0){
                           try {
                               callback.onSuccess(getSslSocketFactory(new ByteArrayInputStream(byteArray)));
                           } catch (Exception e) {
                               callback.onError(e);
                           }
                       }
                    }else {
                        callback.onError(new MySSLException("没有获取到服务器证书"));
                    }
                }
            });
            webView.getSettings().setJavaScriptEnabled(true);
            webView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
            webView.loadUrl(httpsUrl);
        }
    
        private static SSLParams getSslSocketFactory(InputStream... certificates) throws Exception {
            SSLParams sslParams = new SSLParams();
            try {
                TrustManager[] trustManagers = prepareTrustManager(certificates);
                KeyManager[] keyManagers = prepareKeyManager(null, null);
                SSLContext sslContext = SSLContext.getInstance("TLS");
                X509TrustManager trustManager;
                if (trustManagers != null) {
                    trustManager = new MyTrustManager(
                            chooseTrustManager(trustManagers));
                } else {
                    throw new Exception("证书错误");
                }
                sslContext.init(keyManagers,
                        new TrustManager[]{trustManager}, null);
                sslParams.sSLSocketFactory = sslContext.getSocketFactory();
                sslParams.trustManager = trustManager;
                return sslParams;
            } catch (NoSuchAlgorithmException e) {
                throw new AssertionError(e);
            } catch (KeyManagementException e) {
                throw new AssertionError(e);
            } catch (KeyStoreException e) {
                throw new AssertionError(e);
            } catch (Exception e) {
                throw e;
            }
        }
        private static X509TrustManager chooseTrustManager(
                TrustManager[] trustManagers) {
            for (TrustManager trustManager : trustManagers) {
                if (trustManager instanceof X509TrustManager) {
                    return (X509TrustManager) trustManager;
                }
            }
            return null;
        }
        private static TrustManager[] prepareTrustManager(
                InputStream... certificates) {
            if (certificates == null || certificates.length <= 0)
                return null;
            try {
                CertificateFactory certificateFactory = CertificateFactory
                        .getInstance("X.509");
                KeyStore keyStore = KeyStore.getInstance(KeyStore
                        .getDefaultType());
                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) {
                        e.printStackTrace();
                    }
                }
                TrustManagerFactory trustManagerFactory;
                trustManagerFactory = TrustManagerFactory
                        .getInstance(TrustManagerFactory.getDefaultAlgorithm());
                trustManagerFactory.init(keyStore);
                return trustManagerFactory.getTrustManagers();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
        private static KeyManager[] prepareKeyManager(InputStream bksFile,
                                                      String password) {
            try {
                if (bksFile == null || password == null)
                    return null;
                KeyStore clientKeyStore = KeyStore.getInstance("PKCS12");
                clientKeyStore.load(bksFile, password.toCharArray());
                KeyManagerFactory keyManagerFactory = KeyManagerFactory
                        .getInstance(KeyManagerFactory.getDefaultAlgorithm());
                keyManagerFactory.init(clientKeyStore, password.toCharArray());
                return keyManagerFactory.getKeyManagers();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    
        private static class MyTrustManager implements X509TrustManager {
            private X509TrustManager defaultTrustManager;
            private X509TrustManager localTrustManager;
    
            public MyTrustManager(X509TrustManager localTrustManager)
                    throws NoSuchAlgorithmException, KeyStoreException {
                TrustManagerFactory var4 = TrustManagerFactory
                        .getInstance(TrustManagerFactory.getDefaultAlgorithm());
                var4.init((KeyStore) null);
                defaultTrustManager = chooseTrustManager(var4
                        .getTrustManagers());
                this.localTrustManager = localTrustManager;
            }
    
            @Override
            public void checkClientTrusted(X509Certificate[] chain,
                                           String authType) throws CertificateException {
            }
    
            @Override
            public void checkServerTrusted(X509Certificate[] chain,
                                           String authType) throws CertificateException {
                try {
                    defaultTrustManager.checkServerTrusted(chain, authType);
                } catch (CertificateException ce) {
                    localTrustManager.checkServerTrusted(chain, authType);
                }
            }
    
            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return new X509Certificate[0];
            }
        }
    }
    

      

    留作备用,有错误再更正

  • 相关阅读:
    Selenium常用API的使用java语言之7-控制浏览器操作
    Selenium常用API的使用java语言之6-WebDriver常用方法
    Selenium常用API的使用java语言之5-selenium元素定位
    Selenium常用API的使用java语言之4-环境安装之Selenium
    Selenium常用API的使用java语言之3-selenium3 浏览器驱动
    Selenium常用API的使用java语言之2-环境安装之IntelliJ IDEA
    ES6常用七大特性
    css实现类似朋友圈九宫格缩略图完美展示
    NodeJS入门篇
    viewport其实没那么难理解
  • 原文地址:https://www.cnblogs.com/fengchuxiaodai/p/10490775.html
Copyright © 2011-2022 走看看