HTTPS(全称:Hypertext Transfer Protocol over Secure Socket Layer)协议是 HTTP 协议的安全版,在 HTTP 应用层和传输层加入了 SSL/TLS 层,确保数据传输的安全性,所以 HTTPS 协议并不是什么新的协议,仅仅是 HTTP 协议和安全协议的组合。
HTTPS 协议主要解决如下三个通信安全问题:
HTTPS 通过 SSL/TLS 协议解决了上述三个问题,可以达到:
既然安全问题是 SSL/TLS 保证的,那么就有必要仔细探索下 SSL/TLS 协议的机制,如下为 HTTPS 通信的整个网络协议栈,其中 SSL/TLS 协议又分为两层:
关于更多 SSL 和 TLS 知识见之前的文章: 基于 OpenSSL 生成自签名证书。
开始加密通信之前,客户端和服务器首先必须建立连接和交换参数,这个过程叫做握手(handshake)。SSL/TLS 握手其实就是通过非对称加密,生成对称加密的 session key 的过程。
假定客户端叫做爱丽丝服务器叫做鲍勃,整个握手过程可以用下图说明:
整个握手过程通俗地说分为如下五步(真实的过程涉及的细节比这个多):
第一步,爱丽丝给出协议版本号、一个客户端生成的随机数(Client random),以及客户端支持的加密方法。
第二步,鲍勃确认双方使用的加密方法,并给出数字证书、以及一个服务器生成的随机数(Server random)。
第三步,爱丽丝确认数字证书有效,然后生成一个新的随机数(Premaster secret),并使 用数字证书中的公钥,加密这个随机数,发给鲍勃。
第四步,鲍勃使用自己的私钥,获取爱丽丝发来的随机数(即Premaster secret)。
第五步,爱丽丝和鲍勃根据约定的加密方法,使用前面的三个随机数,生成"对话密钥"(session key),用来加密接下来的整个对话过程。
SSL 握手的过程为双方发送消息的过程,这里所说的消息并不是一个独立的 TCP 数据包,而是 SSL 协议的术语。根据服务端实现的不同,可能一个 TCP 包中包含多条消息,而不是每条消息单独发送(每条单独发送效率太低),这个我们后面通过 Wireshark 抓包可以看到。
下图为双方握手过程中互相发送的 SSL 消息:
客户端发送的初始消息
Client Hello 消息
客户端发送 Client Hello 消息给服务端来初始化会话消息,该消息包含如下信息:
服务端响应
Server Hello 消息
服务端回复 Server Hello 消息给客户端:
Server Certificate 消息
服务端发送自己的 SSL 证书给客户端,证书中包含服务端的公钥,客户端用该证书验证服务端的身份。
Server Key Exchange 消息
这个消息是可选的,该消息主要用来传递双方协商密钥的参数,比如双方使用 Diffie-Hellman (迪菲) 算法生成 premaster secret 时,会用该字段传递双方的公共参数。所以具体该字段是什么内容取决于双方协商密钥的加密套件。
Client Certificate Request 消息
这个消息也是可选的,只有当服务端也需要验证客户端会用到。有的安全度高的网站会要求验证客户端,确认客户的真实身份,比如银行之类的网站。
Server Hello Done 消息
服务器发送 ServerHelloDone 消息,告知客户端服务端这边握手相关的消息发送完毕,等待客户端响应。
客户端回复
Client Certificate 消息
如果服务端发送了 Client Certificate Request 消息,那么客户端会发送该消息给服务端,包含自己的证书信息,供服务端进行客户端身份认证。
Client Key Exchange 消息
根据协商的密钥算法不同,该消息的内容会不同,该消息主要包含密钥协商的参数。比如双方使用 Diffie-Hellman (迪菲) 算法生成 premaster secret 时,会用该字段传递双方的公共参数。
Certificate Verify 消息
该消息只有在 Client Certificate message 消息发送时才发送。客户端通过自己的私钥签名从开始到现在的所有发送过的消息,然后服务端会用客户端的公钥验证这个签名。
Change Cipher Spec 消息
通知服务器此消息以后客户端会以之前协商的密钥加密发送数据。
Client Finished 消息
客户端计算生成对称密钥,然后使用该对称密钥加密之前所有收发握手消息的 Hash 值,发送给服务器,服务器将用相同的会话密钥(使用相同方法生成)解密此消息,校验其中的Hash 值。该消息是 SSL 握手协议记录层加密的第一条消息。
服务端最后对客户端响应
Change Cipher Spec 消息
通知客户端此消息以后服务端将会以之前协商的密钥加密发送数据。
Server Finished 消息
服务器使用对称密钥加密(生成方式与客户端相同)之前所发送的所有握手消息的hash值,发送给客户端去校验。
至此 SSL 握手过程结束,双发之后的通信数据都会用双方协商的对称密钥 Session Key 加密传输。
下图为 SSL/TLS 通信的整个过程:TCP 三次握手 + SSL/TLS 握手:
本节使用 wireshark 抓包工具分析一个完整的 HTTPS 通信过程,看看通信过程中双方消息是如何传送的。前面我们说过,根据服务端实现的不同,可能一个 TCP 包中包含多条 SSL/TLS 消息,而不是每条消息单独发送(每条单独发送效率太低)。
使用如下 wireshark https 包过滤器:
tcp.port==443 and (ip.dst==104.18.40.252 or ip.src==104.18.40.252)
下面为 Wireshark 抓取的 https 流量包,展示了整个通信过程:建立 TCP 连接 --> SSL/TLS 握手 --> 应用数据加密传输:
上面是一个实际的 SSL/TLS 握手过程,分为如下 5 步:
下面我们分步分析每个阶段的包的内容,看是否和前面的理论一致。
客户端发送 Client Hello 消息给服务端
可以看出 TLS 协议确实分为两层:TLS 记录层、TLS 握手层,其中 TLS 握手层基于 TLS 记录层。
另外客户端发送的 Client Hello 消息当中包含的信息也可以看到:
服务端回应 Server Hello 消息
Server Hello 包含如下信息:
服务端同时回应 Server Certificate、Server Key Exchange 和 Server Hello Done 消息
可以看出每个 TLS 记录层是一个消息,服务端同时回复了有 3 个消息:Server Certificate、Server Key Exchange、Server Hello Done。
从 Server Key Exchange 消息可以看出双方密钥协商使用的是 Diffie-Hellman (迪菲) 算法,该消息用于传递 Diffie-Hellman (迪菲) 算法的参数。
客户端发送 Client Key Exchange、Change Cipher Spec 和 Client Finished 消息
可以看出客户端同时回复了 3 个消息:Client Key Exchange、Change Cipher Spec 和 Client Finished 消息。Client Key Exchange 的内容为 Diffie-Hellman (迪菲) 算法的参数,用于生成 premaster key,然后和双方之前的随机数结合生成对称密钥。
服务端最后发送 Change Cipher Spec 和 Server Finished 消息
服务端最后发送 Change Cipher Spec 和 Server Finished 消息,至此 SSL/TLS 握手完毕,接下来双方会用对称加密的方式加密传输数据。
https://segmentfault.com/a/1190000002554673 | SSL/TLS 原理详解
http://www.ruanyifeng.com/blog/2014/02/ssl_tls.html | SSL/TLS 协议运行机制概述
http://www.ruanyifeng.com/blog/2014/09/illustration-ssl.html | 图解 SSL/TLS 协议
https://www.jianshu.com/p/a3a25c6627ee | Https详解+wireshark抓包演示
https://segmentfault.com/a/1190000007283514 | TLS/SSL 高级进阶
https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2003/cc785811(v=ws.10) | 微软 Windows 文档