美文网首页
Https四次握手

Https四次握手

作者: feifei_fly | 来源:发表于2018-08-12 18:18 被阅读0次

Https 协议

Https是在Http协议只上 加上了SSL

Http四次握手协议

image

1、客户端请求建立SSL链接,并向服务端发送一个随机数–Client random和客户端支持的加密方法,比如RSA公钥加密,此时是明文传输。

  1. 服务端回复一种客户端支持的加密方法、一个随机数–Server random、授信的服务器证书和非对称加密的公钥。

3.客户端收到服务端的回复后利用服务端的公钥,加上新的随机数–Premaster secret 通过服务端下发的公钥及加密方法进行加密,发送给服务器。

  1. 服务端收到客户端的回复,利用已知的加解密方式进行解密,同时利用Client random、Server random和Premaster secret通过一定的算法生成HTTP链接数据传输的对称加密key – session key。

X509TrustManager 自定义证书信任类:

1、Android 中的证书管理类 是X509TrustManager。

X509TrustManager是一个接口类,自定义证书管理类 需要实现X509TrustManager接口

public interface X509TrustManager extends TrustManager {
   
   /*
   *
   */
    public void checkClientTrusted(X509Certificate[] chain, String authType)
        throws CertificateException;

   
    public void checkServerTrusted(X509Certificate[] chain, String authType)
        throws CertificateException;

    /**
     返回受信任的X509证书数组。
     */
    public X509Certificate[] getAcceptedIssuers();
}

该接口中只有三个方法:

  • checkClientTrusted()
    该方法检查客户端的证书,若不信任该证书则抛出异常。由于我们不需要对客户端进行认证,因此我们只需要执行默认的信任管理器的这个方法。

  • checkServerTrusted
    该方法检查服务器的证书,若不信任该证书同样抛出异常。通过自己实现该方法,可以使之信任我们指定的任何证书。在实现该方法时,也可以简单的不做任何处理,即一个空的函数体,由于不会抛出异常,它就会信任任何证书。

  • getAcceptedIssuers()
    返回受信任的X509证书数组。

2、自定义X509TrustManager

自定义509TrustManager其核心方法为checkServerTrusted 指定信任哪些服务端证书
实现思路如下:

(1)实现一个默认的X509TrustManager,来校验标准的CA证书,若校验通过则return。
(2)若默认509TrustManager 校验CA证书失败。则尝试校验我们是不是我们内置的证书,若校验通过直接return,不抛异常。
(3) 以上两步均为通过,则抛异常,判定证书不合法。

public class MyX509TrustManager implements X509TrustManager {
    private static final String TAG = "MyX509TrustManager";
    /*
     * The default X509TrustManager returned by SunX509.  We'll delegate
     * decisions to it, and fall back to the logic in this class if the
     * default X509TrustManager doesn't trust it.
     */
    private X509TrustManager sunJSSEX509TrustManager;

    //自签名keystore
    private KeyStore truststore;
    private List<X509Certificate> x509caList = new ArrayList<X509Certificate>(1); //存储自签名的 X509证书列表
    private List<InputStream> certificates;//自签名证书 输入流

    public static MyX509TrustManager newInstance(List<InputStream> certificates) {
        return new MyX509TrustManager(certificates);
    }

    private MyX509TrustManager(List<InputStream> certificates) {
        this.certificates = certificates;

        try {

            // create a "default" JSSE X509TrustManager.
            KeyStore ks = KeyStore.getInstance("JKS");

            TrustManager[] tms = new TrustManager[0];
            if (ks != null) {
                FileInputStream is = null;

                try {
                    is = new FileInputStream("trustedCerts");
                    ks.load(is, "passphrase".toCharArray());
                    TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509", "SunJSSE");
                    tmf.init(ks);
                    tms = tmf.getTrustManagers();
                } finally {
                    if (is != null) {
                        try {
                            is.close();
                        } catch (IOException e) {
                            LogUtil.e(TAG, e.getMessage(), e);
                        }

                    }

                    is = null;
                }
            } else {
                TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
                tmf.init((KeyStore) null);
                tms = tmf.getTrustManagers();
            }

            /*
             * Iterate over the returned trustmanagers, look
             * for an instance of X509TrustManager.  If found,
             * use that as our "default" trust manager.
             */
            for (int i = 0; i < tms.length; i++) {
                if (tms[i] instanceof X509TrustManager) {
                    sunJSSEX509TrustManager = (X509TrustManager) tms[i];
                    break;
                }
            }

        } catch (Exception e) {
            try {
                TrustManager[] tms = new TrustManager[0];
                TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
                tmf.init((KeyStore) null);
                tms = tmf.getTrustManagers();
                for (int i = 0; i < tms.length; i++) {
                    if (tms[i] instanceof X509TrustManager) {
                        sunJSSEX509TrustManager = (X509TrustManager) tms[i];
                        break;
                    }
                }
            } catch (Exception e1) {
                LogUtil.e(TAG, "@@@Couldn't initialize https ca JSSE|" + e.getMessage(), e);
            }

        }

        /**
         * 自签名初始化
         */
        this.truststore = createKeyStore(); //将自签名证书 加载KeyStore中
        try {
            Enumeration<String> aliasesIt = truststore.aliases();
            if (aliasesIt != null) {
                while (aliasesIt.hasMoreElements()) {
                    Certificate ca = truststore.getCertificate(aliasesIt.nextElement());

                    // Turn it to X509 format.
                    InputStream is = new ByteArrayInputStream(ca.getEncoded());
                    X509Certificate x509ca1 = (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(is);
                    x509caList.add(x509ca1);

                    //close input stream
                    closeIS(is);
                }
            }
        } catch (Exception e) {
            LogUtil.e(TAG, "@@@Couldn't initialize https ca custom|" + e.getMessage(), e);
        }


    }

    /*
     * Delegate to the default trust manager.
     */
    @Override
    public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
    }

    /*
     * Delegate to the default trust manager.
     */

    @Override
    public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {

        //同时支持可信CA认证和自签名认证(任一种认证通过认为可信)

        boolean ok = false;

        //CA认证
        if (sunJSSEX509TrustManager != null) {
            try {

                sunJSSEX509TrustManager.checkServerTrusted(chain, authType);
                ok = true;
                LogUtil.i(TAG, "@@@@@@@@@@@@@@@@@ ca checkServerTrusted success");
                return;

            } catch (CertificateException e) {
                // do any special handling here, or rethrow exception.
                ok = false;
            }
        }

        //自签名认证
        try {

            for (X509Certificate cert : chain) {

                for (X509Certificate ca : x509caList) {
                    try {

                        cert.verify(ca.getPublicKey());
                        ok = true;
                        LogUtil.i(TAG, "@@@@@@@@@@@@@@@@@ custom checkServerTrusted success");
                        return;

                    } catch (Exception e) {
                        ok = false;
                    }
                }

            }


        } catch (Exception e) {
            // do any special handling here, or rethrow exception.
            ok = false;
        }

        if (!ok) {
            LogUtil.i(TAG, "@@@@@@@@@@@@@@@@@ checkServerTrusted fails");
            throw new CertificateException("https cert verify fails");
        }

    }

    @Override
    public X509Certificate[] getAcceptedIssuers() {
        return sunJSSEX509TrustManager.getAcceptedIssuers();
    }

    private static void closeIS(InputStream is) {
        if (is != null) {
            try {
                is.close();
            } catch (IOException e) {
                LogUtil.e(TAG, e.getMessage(), e);
            }
        }
    }

    /**
     * 得到HTTPS KeyStore
     *
     * @return
     */
    private KeyStore createKeyStore() {


        // https支持
        try {

            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            keyStore.load(null, null);

            int index = 0;

            if (certificates != null && !certificates.isEmpty()) {
                for (InputStream is : certificates) {
                    try {

                        CertificateFactory cerFactory = CertificateFactory.getInstance("X509");
                        Certificate ca = cerFactory.generateCertificate(is);
                        String certificateAlias = Integer.toString(index++);
                        keyStore.setCertificateEntry(certificateAlias, ca);

                    } catch (Exception e) {
                        LogUtil.e(TAG, e.getMessage(), e);
                    } finally {
                        try {
                            if (is != null) {
                                is.close();
                            }
                        } catch (IOException e) {
                            LogUtil.e(TAG, e.getMessage(), e);
                        }
                    }
                }
            }

            return keyStore;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }
}

3、X509TrustManager的使用

//(1)创建SSLContext对象,并使用我们指定的信任管理器初始化
MyX509TrustManager trustManager = new MyX509TrustManager ()
TrustManager[] tm = {trustManager};
SSLContext sslContext = SSLContext.getInstance("SSL","SunJSSE");
sslContext.init(null, tm, new java.security.SecureRandom());

//(2)从上述SSLContext对象中得到SSLSocketFactory对象
SSLSocketFactory ssf = sslContext.getSocketFactory();

//(3) 设置OkhttpClient的sslSocketFactory

        OkHttpClient client = new OkHttpClient.Builder()
                .connectTimeout(TimeOut, TimeUnit.SECONDS)
                .readTimeout(TimeOut,TimeUnit.SECONDS)
                .writeTimeout(TimeOut,TimeUnit.SECONDS)
                .sslSocketFactory(ssf, trustManager)//https证书认证
                .hostnameVerifier(new HttpsUtils.MyHostnameVerifier())//自定义了HostnameVerifier。在握手期间,如果 URL 的主机名和服务器的标识主机名不匹配,则验证机制可以回调此接口的实现程序来确定是否应该允许此连接。
                .addInterceptor(MakeupInterceptor.newInstance())
                .build();
        Retrofit retrofit = new Retrofit.Builder()
                .client(client)
                .baseUrl(URL)
                .addConverterFactory(ResponseConvertFactory.create())
               .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .build();
         retrofit.create(RequestService.class);
    

Chares 大花瓶 抓包原理

实际上 Chares 作为中间人代理,对客户端伪装服务器,通知对服务器伪装客户端。

  • 截获真实客户端的HTTPS请求,伪装客户端向真实服务端发送HTTPS请求
  • 接受真实服务器响应,用Charles自己的证书伪装服务端向真实客户端发送数据内容

关键的两点:

  • 需要为手机设置代理,这样手机所有的请求都会路由到Chares
  • 需要在手机端下载Chares自制的私有CA证书,并设置为信任证书。这样Chares可以伪装服务器 与客户端进行四次握手,建立https链接

参考链接:

https://www.zybuluo.com/Sweetfish/note/706401
https://www.jianshu.com/p/870451cb4eb0

相关文章

  • Https四次握手

    Https 协议 Https是在Http协议只上 加上了SSL Http四次握手协议 1、客户端请求建立SSL链接...

  • tcp

    报文结构、三次握手、四次挥手 Tcp--三次握手,四次挥手[https://www.jianshu.com/p/a...

  • iOS 网络

    Http的报文结构 Https的4次握手过程 Cookie/Session TCP、三次握手、四次挥手、代码实现 ...

  • TCP连接和关闭过程

    TCP三次握手过程及四次挥手过程 HTTPS加密请求过程

  • 计算机基础优秀文章

    1 、 TCP三次握手四次挥手:https://zhuanlan.zhihu.com/p/86426969

  • 计算机网络知识目录

    · TCP/IP协议模型 TCP 三次握手四次挥手 四元组 · Http · Https

  • 2022-03-24

    三次握手与四次挥手[https://blog.csdn.net/whuslei/article/details/6...

  • 2、tcpdump抓包分析三次握手和四次挥手

    TCP为什么需要三次握手、四次挥手 三次握手 三次握手 四次挥手 SYN flood攻击

  • TCP 三次握手和四次挥手

    TCP三次握手四次挥手详解[https://www.cnblogs.com/zmlctt/p/3690998.ht...

  • HTTP

    一、HTTP 二、HTTPS 三、HTTP报文 四、HTTPS 的安全通信机制 五、数字签名 六、三次握手&四次挥...

网友评论

      本文标题:Https四次握手

      本文链接:https://www.haomeiwen.com/subject/dctebftx.html