Https浅析

      网络请求是我们日常工作中比不可少的部分,http一般大家都熟练掌握,但https可能有不少同学有一些疑惑。先结合我在使用https的过程中遇到的问题来浅析一下https。主要问题有以下几点:

1.SSL和TLS的区别:

SSL:(Secure Socket Layer,安全套接字层),位于可靠的面向连接的网络层协议和应用层协议之间的一种协议层。SSL通过互相认证、使用数字签名确保完整性、使用加密确保私密性,以实现客户端和服务器之间的安全通讯。该协议由两层组成:SSL记录协议和SSL握手协议。

TLS:(Transport Layer Security,传输层安全协议),用于两个应用程序之间提供保密性和数据完整性。该协议由两层组成:TLS记录协议和TLS握手协议。

SSL于2014年4月8日曝出严重的安全漏洞。这个漏洞使攻击者能够从内存中读取多达64 KB的数据。所以我们可以简单的认为TLS是SSL的升级版本

2.https请求过程中客户端和服务端的握手

首先来看一组https请求的抓包:

从上图可以清晰的看出客户端和服务端的握手过程:

1.客户端向服务器发送一个Client Hello的请求,请求中包含一个随机数以及协议版本号等信息,服务器会保存这个随机数;

2.服务器收到请求后,会发送一个server Hello响应给客户端,响应信息也包含一个随机数,此时服务器和客户端都有两个随机数;

3.服务器会继续发送一个证书给客户端,客户端拿到证书后会做一下几个动作:

    ① 客户端拿到证书后会提取证书中的公钥;

    ② 客户端拿到公钥后会随机生成一个随机数,并且会用公钥对随机数加密;

4.客户端会把加密后的随机数发送给服务器,服务器用私钥解密也获取到随机数;这样客户端和服务端都有3个随机数,并且用这三个随机数生成发送数据的会话密码;

5.客户端和服务器就可以用会话密码进行数据交互;

通过上面的分析,我们再用一个图来描述,让大家能更形象的理解:

3.单向验证与双向认证

单向认证:简单可以理解为客户端信任服务器端的证书,服务器不用验证客户端;

双向认证:客户端信任服务端证书,服务端也信任客户端证书;

4.加载自制证书和使用默认预置证书的代码

① 使用默认的预置证书

@Test

public void doHttps()throws Exception{

String path ="https://restapi.amap.com/v3/weather/weatherInfo?city=深圳&key=13eb58f5884f9749287abbead9c658f2";

    HttpUrl httpUrl =new HttpUrl(path);

    //如果证书是Android手机已经预置的则只需要一下操作:

    SSLContext sslContext = SSLContext.getDefault();

    SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();

    Socket socket = sslSocketFactory.createSocket(httpUrl.getHost(), httpUrl.getPort());

    final InputStream ins = socket.getInputStream();

    OutputStream os = socket.getOutputStream();

    new Thread(){

@Override

        public void run() {

//获取服务器数据

            BufferedReader br =new BufferedReader(new InputStreamReader(ins));

            String line;

            try{

while ((line = br.readLine()) !=null){

System.out.println(line);

                }

}catch (Exception e){

e.printStackTrace();

            }

}

}.start();

    os.write(("GET " + httpUrl.geFile() +" http/1.1\r\n").getBytes());

    os.write(("Host: " + httpUrl.geFile() +"\r\n\r\n").getBytes());

    os.flush();

    //单元测试不会等线程

    while (true){}

}

②自制证书加载的过程:

//@Test

public void doCustomHttps()throws Exception{

String path ="http://restapi.amap.com/v3/weather/weatherInfo?city=深圳&key=13eb58f5884f9749287abbead9c65";

    HttpUrl httpUrl =new HttpUrl(path);

    //自制证书加载的过程:

    SSLContext sslContext = SSLContext.getInstance("TLS");

    //信任管理工厂

    TrustManagerFactory trustManagerFactory =  TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());

    KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());

    keyStore.load(null);

    //证书工厂

    CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");

    FileInputStream fis =new FileInputStream("D:\\xx.cer");

    X509Certificate certificate = (X509Certificate) certificateFactory.generateCertificate(fis);

    keyStore.setCertificateEntry("xinlian", certificate);

    trustManagerFactory.init(keyStore);

    //第一个参数为客服端证书  第二个参数为服务器证书  第三个参数是随机数

    //此处我们为单向认证所以第一个参数不用传

    sslContext.init(null, trustManagerFactory.getTrustManagers(), null);

    SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();

    Socket socket = sslSocketFactory.createSocket(httpUrl.getHost(), httpUrl.getPort());

    final InputStream ins = socket.getInputStream();

    OutputStream os = socket.getOutputStream();

    new Thread(){

@Override

        public void run() {

//获取服务器数据

            BufferedReader br =new BufferedReader(new InputStreamReader(ins));

            String line;

            try{

while ((line = br.readLine()) !=null){

System.out.println(line);

                }

}catch (Exception e){

e.printStackTrace();

            }

}

}.start();

    os.write(("GET " + httpUrl.geFile() +" http/1.1\r\n").getBytes());

    os.write(("Host: " + httpUrl.geFile() +"\r\n\r\n").getBytes());

    os.flush();

    //单元测试不会等线程

    while (true){}

}

以上就是对https的一点理解,如果有不正确的地方请大家指正,谢谢!

你可能感兴趣的:(Https浅析)