TCP、TLS\SSL、JSSE、HTTPS杂烩笔记

目录

TCP

简介

一个数据包的旅程

TCP如何保证数据的可靠和完整

确认应答和序列号

超时重传

流量控制

TCP报文格式

三次握手建立连接

建立了什么样的连接

三次握手

为什么是三次握手

四次挥手

WireShark抓包

TLS

单向认证

双向认证

ALPN

JSSE

单向认证代码

双向认证代码

WireShark分析

单向认证

双向认证

Tomcat配置HTTPS访问


以目前我的理解以及这两天的各种百度写个总结笔记,有不对的请指正

TCP

简介

全名Transmission Control Protocol,传输控制协议,是网络层IP协议和链路层Ethernet协议之上,Ethernet协议实现链路层的数据传输和地址封装(源方和目标方的MAC地址),解决局域网的点对点通信,而不同局域网之间的两台机子则需要IP协议进行地址的路由中转,TCP则面向的是端口到端口,保证数据传输的完整和可靠,包括数据包的确认、失败重发、流量控制,数据量大的情况TCP会将数据拆分为有序的多个数据包传输,TCP需要能将数据包重组为完整的数据

一个数据包的旅程

        本机浏览器写个url准备回车,此时本机都有什么信息,本机的mac、ip、浏览器应用的端口自然是知道的,url里只有对方的域名,浏览器形成了HTTP报文数据之后,委托给操作系统进行处理并发送,但是操作系统只认IP,不认域名,所以在委托之前还需要查询对方域名的IP地址,也就是DNS服务器(url是ip+port也就不需要解析了),浏览器向DNS询问出IP之后,交给操作系统。

        操作系统收到委托,首先TCP处理,数据太多切割成多份,为每份增加一些 保证数据传输的完整和可靠所必要的信息头,例如源端口和目标端口,数据包的序号,本机当前可接收的最大数据量等等。

        其次IP协议为每份TCP处理过的包再加上ip包头,例如本机IP地址和对方IP地址,最后需要为数据包加上目标的物理mac地址。

        此时判断对方IP地址是不是同一个局域网,如果是,那么使用ARP(地址解析协议)在局域网广播,IP是XXXX.XXX.XX.X是谁的,局域网其他主机收到包,其中一个主机发现说的是自己,回复我在这,mac地址是YYYY,这样就可以为数据包加上mac头交给网卡转换成电信号由网线传输给目标主机,每次都广播显然不合理,所以主机会维护一个arp表记录ip和mac的对应关系。如果不是一个局域网,那么就需要网关来转发数据包,所以mac地址就需要写网关的mac地址,也是一样ARP广播的是网关的IP。

        此时数据包已经完成组装发出,网关收到以后拆开最外层的包头,发现确实是发给自己的,在拆开第二层,目的IP不是自己,从自己的路由表查找目的IP对应的MAC地址,有就直接写目的mac,没有则写下一个网关的mac地址,重新封上两层数据包头,发出去。一次一次的接力最终把数据包发送给目标主机。

        目标主机再一层层解析,解析TCP报头,了解了目标端口,查下本机发现这个端口是一个Tomcat服务器在监听,则把按数据包序号重新组织好的数据发送给Tomcat进程,Tomcat处理完毕,再将响应返回给操作系统,操作系统重新一层层组织好数据包头,由网卡再发送回去。

TCP如何保证数据的可靠和完整

确认应答和序列号

TCP给发送的每一个包添加报文头时,会进行编号seq,这样接收方接收到被拆分后的数据后,按照序号seq对数据包进行排序,数据重组后把有序数据传送给应用层

并且接收方会对收到的报文回复确认ack,确认时会带有确认序号,表示此确认序号之前的所有数据我已收到,下次请给我发这个序号之后的数据。

确认并不是每收到一个数据包就返回一次ack,如果是这样,那么网络中就会存在一半数据,一半确认,而且确认大多都是没有必要的。发送方可以一次性发送多个数据包,接收方若接受正常,只需要发送一次ack

超时重传

发送数据包之后,若一定时间没有收到接收放的ack确认消息,则会重新发送数据包,那么有两种可能没有收到ack,1接收方没有收到数据,2接收方的ack传输中丢失了,在第一种情况,重新发送接收方若收到,发ack,发送方收到继续下一批数据的发送,若第二种情况,接收方接收到相同序号seq的数据,直接丢弃不处理,仍发送ack。所以序号既排序也作为去重的依据。

流量控制

发送端和接收端处理数据的速度不一致,发送端发送的太快,接收端处理不过来导致丢包,那么发送端长时间等不到ack,超时重传形成一个恶性循环。根据接收端对数据的处理能力,决定发送端的发送速度,这个机制就是流量控制。

在确认报文中,接收方会回复给发送方一个窗口大小,表示我最多接收这么点数据,接收方处理不过来时,窗口缩小,发送方根据这个大小控制自己发送的频率和数据量

滑动窗口

即上边流量控制中的说的窗口,用于网络数据传输时的流量控制,以避免拥塞的发生

TCP、TLS\SSL、JSSE、HTTPS杂烩笔记_第1张图片

分为四段,已发送并已被确认的数据, 已发送未收到确认的数据,还未发送但可以发送的数据,不可发送的数据。其中第二段和第三段就是当前窗口的大小,当前大小为51 - 32 + 1 = 20。此时如果发送方接收到ack回复ack=34 win=21,其中win就是接收方窗口大小,接收方条件好些了比上次可以多接收一个字节,此时窗口向右滑动,即就是28--34为第一段,35--55就是新的窗口大小,大小为21。

TCP报文格式

TCP、TLS\SSL、JSSE、HTTPS杂烩笔记_第2张图片

两个端口,代表了两台主机的两个进程;

两个序号,第一个代表发送端本次数据包的序号,确认序号表示发送端希望下次收到接收端的报文序号;

4位首部长度,表示tcp头多少个字节

6位标志位,常见的就是ACK,SYN,FIN,RST

  • URG: 本报文段中发送的数据是否包含紧急数据
  • ACK: 标识确认序号是否有效,1确认序号有效,0无效忽略确认号
  • PSH: 为1时用来提示接收端应用程序立刻将数据从tcp缓冲区读走
  • RST: 要求重新建立连接,通常发生在某一端出现错误的情况,强制关闭连接
  • SYN: 请求建立连接
  • FIN: 通知接收方, 发送方没有数据了,即将关闭连接

16位窗口大小,滑动窗口最大65535字节

16位检验和,由发送端填充,校验数据包中数据是否正确

16位紧急指针, 标记紧急数据在数据字段中的位置

 选项,对tcp的扩展,例如最大报文长度、窗口扩大比例等。窗口扩大比例是指,当前65535的窗口大小已经不满足通信需要,如果存在窗口扩大比例选项,那么窗口大小就是16位窗口大小乘以这个选项中的比例。

三次握手建立连接

建立了什么样的连接

TCP是面向连接的通信,上述的数据包路径来看,TCP建立的并不是两台主机间什么直接的物理上实际的连接,只能算有链接特性的、互相维持的一个状态。 双方都存有此次连接的相关数据,例如需要保证数据传输的完整和可靠,需要一些数据结构来支持数据包的确认、失败重发、重组等。

而完整和可靠的连接保证,需要复杂的连接建立交互过程,在交互过程中协商、初始化各种信息来让双方达到一个共识,确保后续数据的正常处理。

三次握手

TCP、TLS\SSL、JSSE、HTTPS杂烩笔记_第3张图片

服务器端状态当前为LISTEN监听端口,客户端先发送请求建立连接报文,SYN标志为1,附带客户端初始序列号seq=x,并进入 SYN-SENT(同步已发送状态)

服务端收到连接报文,若同意建立连接,同样回复建立连接报文,SYN标志为1,附带确认信息,ACK标志为1,服务端初始序列号seq=y,希望下次收到客户端序列号ack=x+1,进入SYN-RCVD(同步收到)状态

客户端收到回复确认ACK标志为1,客户端序号为上次发送的x+1,希望下次收到服务端包序号为y+1,进入ESTABLISHED(已建立连接)状态,服务端收到后也进入ESTABLISHED(已建立连接)状态,开始发送数据。

序列号不是都从0开始,只是示例。为什么都是序列号+1,因为三次握手是建立共识的过程,不允许携带数据但消耗一个序列号,如果是建立连接之后,包中有数据,例如客户端发送seq=6, ack=20,数据大小为30,那么服务端接收到后回复确认就是seq=20,ack=36,客户端下次发送的序号就是36

为什么是三次握手

TCP是可靠的,精髓在于序列号,A向B建立连接,告诉B我的序列号是从5000开始的,那么B在后续接收处理时,就知道5000之前的数据是错误该丢弃的,同时回复A确认以及B的初始序列号,A就知道我的初始序号已经成功传输,同时回复B确认,此刻AB双方才都对初始序列号达成共识,后续才能开展可靠传输。

因此,建立连接需要四个步骤,A发送A的初始序列号,B收到并回复确认,B发送B的初始序列号,A收到并回复确认,建立共识。第二和第三可以合并,因此是三次握手。

假设两次握手,也就是说A请求,B响应,此连接就算建立,此时B对A的初始序列号已经知晓,但并不知道A是否收到自己的初始序列号,连接是不可靠的。

四次挥手

A,B双方都可以发起连接的关闭

1、A向B发送FIN报文,表示A已经没有数据要发送了,准备关闭连接

2、B收到后回复确认ACK,表示知道了,此时可能B中还存在部分未发送完的数据,此时B继续发送,A仍需要接收

3、B向A发送FIN报文,表示B也没有数据了,准备关闭连接,等待最后的确认

4、A收到FIN,回复确认并关闭连接,B收到确认也关闭连接

三次握手是因为第二第三阶段可以合并发送,所以减少了一次交互,而四次挥手因为接收到对方的FIN时,只表示了对方不再发送数据给自己,还可以接收,而且自己的数据也可能没有发送完毕,从而导致多发生了一次挥手。

WireShark抓包

三次握手、两次传输数据、四次挥手的示例

TCP、TLS\SSL、JSSE、HTTPS杂烩笔记_第4张图片

下方为一次SYN请求的数据报文,两个16进制数为一个字节,按照报文头结构,前两字节为源端口,也就是d7 1c 即55068,24 2a 为9258

TCP、TLS\SSL、JSSE、HTTPS杂烩笔记_第5张图片

SYN标志位1,滑动窗口大小fa f0 即64240

 TCP、TLS\SSL、JSSE、HTTPS杂烩笔记_第6张图片

在选项中,定义了窗口缩放比例为2^8=256, 即握手之后传输数据,窗口大小为WIN * 256

TCP、TLS\SSL、JSSE、HTTPS杂烩笔记_第7张图片

 再来看序号的增加,第一次HTTP请求中seq==1,ack==1,报文中携带数据长度320

TCP、TLS\SSL、JSSE、HTTPS杂烩笔记_第8张图片

 那么对应HTTP响应的TCP头的ack中的确认序号就是ack==321,表示320的数据已收到,下次来321,此次ack中seq==1,数据长度444

 那么下次的回复可以推断出seq==321,ack=445,看报文确实

序列号是从0开始这只是相对序列号,如果想看真实序列号,wireshark-》编辑-》首选项-》协议-》TCP,不勾选下边这个选项,即可看见眼花缭乱的序号

TLS

        SSL(Secure Socket Layer 安全套接层)是属于应用层下,TCP传输层之上的一个协议加密层,最初是由网景公司(Netscape)研发,在SSL更新到3.0时,IETF(The Internet Engineering Task Force - 互联网工程任务组)对SSL3.0进行了标准化,并添加了少数机制(但是几乎和SSL3.0无差异),标准化后的IETF更名为TLS1.0(Transport Layer Security 安全传输层协议),可以说TLS就是SSL的新版本

    没有使用SSL加密的消息通讯因为都是明文传输,通讯过程容易被监听、修改或者身份冒充遭到中间人攻击等。TLS就是解决安全传输问题的解决方案,核心思想是非对称加密,通讯双方都使用对方公钥加密消息,私钥签名,接受到消息后使用私钥解密,公钥验证签名,并辅以CA签发证书来验证双方身份,这样即解决了上述安全问题。

        但是非对称加密算法计算量太大,每一次的消息都使用公钥私钥加密对性能损耗极大,因此解决方法就变成了 : 双方协商生成一个对称密钥,对称密钥运算速度块,由公私密钥加密传输这个对称密钥,这样双方之后的交互就是用这个对称密钥进行加密通讯。

在JSSE节,会wireShark抓包来分析真正交互的各个阶段,下边只是描述大概

单向认证

也即只是客户端验证服务端身份,大致一次的通讯过程为:

1、TCP三次握手建立连接

2、客户端向服务端发送建立SSL请求,表明自己支持的所有加密方式,并请求获取服务端证书

3、服务端接收请求,选择一种加密方式以及附带证书响应给客户端

4、客户端验证服务端证书可信,生成对称密钥,使用服务端公钥加密后发送给服务端

5、服务端接收到加密的对称密钥,使用客户端证书解签认证,使用私钥解密后得到对称密钥

6、开始使用对称密钥加密通信

双向认证

双向认证即服务端也需要验证客户端身份,加粗为与单向区别

1、TCP三次握手建立连接

2、客户端向服务端发送建立SSL请求,表明自己支持的所有加密方式,并请求获取服务端证书

3、服务端接收请求,选择一种加密方式以及附带证书响应给客户端,并请求获取客户端证书

4、客户端验证服务端证书可信,生成对称密钥,使用服务端公钥加密后附带客户端证书发送给服务端

5、服务端接收到加密的对称密钥和客户端证书,验证证书可信,使用客户端证书解签认证,使用私钥解密后得到对称密钥

6、开始使用对称密钥加密通信

ALPN

Application Layer Protocol Negotiation,应用层协议协商,双方协商在安全连接之上的应用层协议,TLS的扩展,类似TCP对滑动窗口大小的扩展,在TLS握手中,客户端会会发送给服务端客户端所支持的协议列表,服务端从中选择自己支持的协议类型响应给客户端

下图是抓包截图,客户端在请求安全连接之时,附带自己支持的应用层协议列表,下图为http2和http/1.1

TCP、TLS\SSL、JSSE、HTTPS杂烩笔记_第9张图片  服务端响应时从中选择支持的协议

TCP、TLS\SSL、JSSE、HTTPS杂烩笔记_第10张图片

JSSE

Java Secure Socket Extension (Java安全套接字扩展

它包含了实现Internet安全通信的一系列包的集合,是SSL和TLS的Java实现

JSSE API 类图如下,SSLServerSocket/SSLSocket继承ServerSocket/Socket,表示实现了SSL协议的Socket,负责安全会话握手等,封装了底层复杂的安全通信细节

代码示例见博文:

TCP、TLS\SSL、JSSE、HTTPS杂烩笔记_第11张图片

测试代码,首先需要产生两对keystore

client.keystore  客户端密钥对所在的密钥库

client_trust.keystore  客户端所信任的证书库

server.keystore  服务端密钥对所在库

server_trust.keystore 服务端所信任的证书库

产生客户端密钥对

keytool -genkeypair -alias client -keypass client -keyalg RSA -keysize 1024
 -validity 365 -keystore D:\java\keystore\client.keystore -storepass client

TCP、TLS\SSL、JSSE、HTTPS杂烩笔记_第12张图片

导出客户端证书,只包含客户端公钥

keytool -export -alias client -keystore D:\java\keystore\client.keystore -file D:\java\keystore\client.crt -storepass client

将客户端证书导入到 服务端信任库中server_trust.keystore

keytool -import -alias client -file D:\java\keystore\client.crt -keystore D:\java\keystore\server_trust.keystore -storepass server_trust 

产生服务端密钥对

keytool -genkeypair -alias server -keypass server -keyalg RSA -keysize 1024 -validity 365 -keystore D:\java\keystore\server.keystore -storepass server

导出服务端证书,只包含服务端公钥

keytool -export -alias server -keystore D:\java\keystore\server.keystore -file D:\java\keystore\server.crt -storepass server

将服务端证书导入到 客户端信任库中client_trust.keystore

keytool -import -alias server -file D:\java\keystore\server.crt -keystore D:\java\keystore\client_trust.keystore -storepass client_trust 

单向认证代码

服务端代码


import javax.net.ssl.*;
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.*;

public class server {
    public static void main(String[] args) throws Exception {
        // 服务端密钥库初始化
        KeyStore serverKeyStore = KeyStore.getInstance("JKS");//证书库格式
        serverKeyStore.load(new FileInputStream("D:\\java\\keystore\\server.keystore"), "server".toCharArray());//加载密钥库
        KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");//证书格式
        kmf.init(serverKeyStore, "server".toCharArray());//加载密钥储存器

        //SSL上下文对象创建
        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(kmf.getKeyManagers(),null, null);

        //由上下文对象创建服务端sslSocket
        SSLServerSocketFactory serverFactory = sslContext.getServerSocketFactory();
        SSLServerSocket svrSocket = (SSLServerSocket) serverFactory.createServerSocket(8989);
        // svrSocket.setEnabledCipherSuites(new String[]{"TLS_RSA_WITH_AES_256_CBC_SHA"});

        System.out.println("SSL端口监听中。。。");
        SSLSocket cntSocket = (SSLSocket) svrSocket.accept();

        //读入客户端消息
        InputStream in = cntSocket.getInputStream();
        byte[] bytes = new byte[102];
        in.read(bytes);
        System.out.println("来自于客户端:" + new String(bytes, "UTF-8"));
    }
}

客户端代码

import javax.net.ssl.*;
import java.io.FileInputStream;
import java.io.OutputStream;
import java.security.KeyStore;

public class client {

    public static void main(String[] args) throws Exception {
        //信任库 初始化
        KeyStore serverKeyStore = KeyStore.getInstance("JKS");
        serverKeyStore.load(new FileInputStream("D:\\java\\keystore\\client_trust.keystore"), "client_trust".toCharArray());

        TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
        tmf.init(serverKeyStore);

        //SSL上下文对象
        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, tmf.getTrustManagers(), null);

        // 由上下文对象创建安全的socket对象
        SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
        SSLSocket sslSocket= (SSLSocket) sslSocketFactory.createSocket("localhost", 8989);

        //发送消息
        OutputStream out=sslSocket.getOutputStream();
        out.write("你好你好兄弟".getBytes("UTF-8"));
    }
}

双向认证代码

服务端代码,与单向认证区别,在于需要加载服务端信任库,由此去验证客户端身份,以及设置setNeedClientAuth(true),表明需要验证客户端身份


import javax.net.ssl.*;
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.KeyStore;

public class server {
    public static void main(String[] args) throws Exception {
        // 服务端密钥库
        KeyStore serverKeyStore = KeyStore.getInstance("JKS");//证书库格式
        serverKeyStore.load(new FileInputStream("D:\\java\\keystore\\server.keystore"), "server".toCharArray());//加载密钥库
        KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");//证书格式
        kmf.init(serverKeyStore, "server".toCharArray());//加载密钥储存器

        // 服务端信任库
        KeyStore clientKeyStore = KeyStore.getInstance("JKS");
        clientKeyStore.load(new FileInputStream("D:\\java\\keystore\\server_trust.keystore"), "server_trust".toCharArray());
        TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
        tmf.init(clientKeyStore);

        //SSL上下文对象创建
        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(kmf.getKeyManagers(),tmf.getTrustManagers(), null);

        //由上下文对象创建服务端sslSocket
        SSLServerSocketFactory serverFactory = sslContext.getServerSocketFactory();
        SSLServerSocket svrSocket = (SSLServerSocket) serverFactory.createServerSocket(8989);
        svrSocket.setNeedClientAuth(true);// 设置为true,服务端需要验证客户端身份

        System.out.println("SSL端口监听中。。。");
        SSLSocket cntSocket = (SSLSocket) svrSocket.accept();

        //读入客户端消息
        InputStream in = cntSocket.getInputStream();
        byte[] bytes = new byte[102];
        in.read(bytes);
        System.out.println("来自于客户端:" + new String(bytes, "UTF-8"));
    }
}

客户端代码,与单向区别在于需要加载客户端的密钥库,因为需要给服务端发送客户端证书

import javax.net.ssl.*;
import java.io.FileInputStream;
import java.io.OutputStream;
import java.security.KeyStore;

public class client {

    public static void main(String[] args) throws Exception {
        // 客户端密钥库
        KeyStore clientKeyStore = KeyStore.getInstance("JKS");
        clientKeyStore.load(new FileInputStream("D:\\java\\keystore\\client.keystore"), "client".toCharArray());
        KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
        kmf.init(clientKeyStore, "client".toCharArray());

        // 客户端信任库
        KeyStore serverKeyStore = KeyStore.getInstance("JKS");
        serverKeyStore.load(new FileInputStream("D:\\java\\keystore\\client_trust.keystore"), "client_trust".toCharArray());
        TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
        tmf.init(serverKeyStore);

        //SSL上下文对象创建
        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);

        // 创建socket
        SSLSocketFactory sslcntFactory = sslContext.getSocketFactory();
        SSLSocket sslSocket= (SSLSocket) sslcntFactory.createSocket("localhost", 8989);

        //发送消息
        OutputStream out=sslSocket.getOutputStream();
        out.write("你好你好兄弟".getBytes("UTF-8"));
    }
}

WireShark分析

单向认证

上边测试代码中服务端有一行注释代码,目的是为了指定服务端选择的加密套件

选择了TLS_RSA_WITH_AES_256_CBC_SHA,即对称密钥交换算法使用RSA,身份认证算法使用RSA,对称加密算法使用AES_256_CBC,摘要算法使用SHA。

再比如TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,密钥交换算法使用ECDHE,身份认证算法使用RSA,对称加密算法使用AES_256_CBC,摘要算法使用SHA384。

不同的加密套件,有不同的算法,交互流程也会有些微的不同,不过基本差不多,下面截图的加密套件是TLS_RSA_WITH_AES_256_CBC_SHA

TCP、TLS\SSL、JSSE、HTTPS杂烩笔记_第13张图片

 1、Client Hello

发送给服务端一个随机数,稍后用于产生对称密钥,还有自己支持的所有加密套件(图例43个)

TCP、TLS\SSL、JSSE、HTTPS杂烩笔记_第14张图片

2、Server Hello / Certificate / Server Hello Done

   1)server hello 

    服务端生成session保存握手信息,返回客户端一个随机数,SessionID和选中的加密套件

    随机数稍后用于产生对称密钥,sessionID用于会话复用

TCP、TLS\SSL、JSSE、HTTPS杂烩笔记_第15张图片

   2) certificate

     服务端公钥证书返回给客户端

    3) server hello done

     只是个标识,告诉客户端,首次握手事完了

3、Client Key Exchange

     客户端验证证书后,再次生成一个随机数,使用服务端公钥加密后发送给服务端,此时客户端已经知道三个随机数了, 根据协商的算法计算出对称密钥

    为什么需要计算对称密钥需要三个随机数,百度说是为了增加随机性

4、(C --> S) Change Cipher Spec

编码改变通知,标识我要使用对称密钥加密传输数据了

5、(C --> S) Encrypted Handshake Message

客户端握手结束通知,表示客户端的握手阶段已经结束。对前面发送的所有内容的进行hash,用来供服务器校验

TCP、TLS\SSL、JSSE、HTTPS杂烩笔记_第16张图片

6、(S --> C) Change Cipher Spec

服务端接收到第三个随机数后,计算出相同的对称密钥,通知客户端可以使用对称密钥加密传输数据了

7、(S --> C) Encrypted Handshake Message

同5

双向认证

TCP、TLS\SSL、JSSE、HTTPS杂烩笔记_第17张图片

 比单向认证中,server hello阶段多了几步

Server Key Exchange 

这是因为server hello选择的加密套件为TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 ,

ECDHE椭圆曲线算法特有步骤,具体啥未详细了解,告诉客户端一个数用来计算对称密钥

TCP、TLS\SSL、JSSE、HTTPS杂烩笔记_第18张图片

Certificate Request

服务端请求客户端证书,并告诉客户端签名和摘要算法使用下边列举的

TCP、TLS\SSL、JSSE、HTTPS杂烩笔记_第19张图片

Certificate Verify

客户端发送证书后,选择一种算法,发送一个签名信息向服务端表明证书属于自己

TCP、TLS\SSL、JSSE、HTTPS杂烩笔记_第20张图片

 其他交互和单向一致

Tomcat配置HTTPS访问

使用上一节jsse生成的证书, Tomcat8.5

配置Tomcat的server.xml

配置连接器Connector的证书为server.keystore

    
      
        
      
    

启动项目,访问controller,发现http已经不能使用了

TCP、TLS\SSL、JSSE、HTTPS杂烩笔记_第21张图片

https可以正常访问,但是会提示不安全,这是因为浏览器不信任服务端证书TCP、TLS\SSL、JSSE、HTTPS杂烩笔记_第22张图片

证书如下,因为我上述证书是随意生成的,证书颁发给谁随意填写的,所以如下双击安装了证书后依旧不安全,现重新keytool生成一个

TCP、TLS\SSL、JSSE、HTTPS杂烩笔记_第23张图片TCP、TLS\SSL、JSSE、HTTPS杂烩笔记_第24张图片

如下新创建一个,在姓名姓氏那里填写浏览器要访问的地址或域名,再导出证书,安装证书,修改server.xml中证书信息

TCP、TLS\SSL、JSSE、HTTPS杂烩笔记_第25张图片

TCP、TLS\SSL、JSSE、HTTPS杂烩笔记_第26张图片

再次访问路径,发现不是非安全了

TCP、TLS\SSL、JSSE、HTTPS杂烩笔记_第27张图片 额,ie是好了,但是谷歌依旧不安全,暂时不知道为啥

你可能感兴趣的:(笔记,ssl,https)