HTTP 由于是明文传输,所谓的明文,就是说客户端与服务端通信的信息都是肉眼可见的,随意使用一个抓包工具都可以截获通信的内容。
所以安全上存在以下三个风险:
窃听风险,比如通信链路上可以获取通信内容,用户号容易没。
篡改风险,比如强制植入垃圾广告,视觉污染,用户眼容易瞎。
冒充风险,比如冒充淘宝网站,用户钱容易没。
HTTPS 在 HTTP 与 TCP 层之间加入了 TLS 协议,来解决上述的风险。
谁来加密 加密密钥 ,加密密钥如何从客户端安全传输到服务端,客户端如何识别服务端的合法性,传输信息如何高效进行
TLS 协议是如何解决 HTTP 的风险的呢?
-信息加密:HTTP 交互信息是被加密的,第三方就无法被窃取;
校验机制:校验信息传输过程中是否有被第三方篡改过,如果被篡改过,则会有警告提示;
身份证书:证明淘宝是真的淘宝网;
可见,有了 TLS 协议,能保证 HTTP 通信是安全的了,那么在进行 HTTP 通信前,需要先进行 TLS 握手。TLS 的握手过程,如下图:
上图简要概述来 TLS 的握手过程,其中每一个「框」都是一个记录(*record*),记录是 TLS 收发数据的基本单位,类似于 TCP 里的 segment。多个记录可以组合成一个 TCP 包发送,所以**通常经过「四个消息」就可以完成 TLS 握手,也就是需要 2个 RTT 的时延**,然后就可以在安全的通信环境里发送 HTTP 报文,实现 HTTPS 协议。
## 二、RSA密钥协商握手过程
TLS 第一次握手
客户端首先会发一个「**Client Hello**」消息,字面意思我们也能理解到,这是跟服务器「打招呼」。
消息里面有客户端使用的 TLS 版本号、支持的密码套件列表,支持的压缩算法,以及生成的**随机数(\*Client Random\*)**,这个随机数会被服务端保留,它是生成对称加密密钥的材料之一。
#### TLS 第二次握手
当服务端收到客户端的「Client Hello」消息后,会确认 TLS 版本号是否支持,和从密码套件列表中选择一个密码套件,还有选择压缩算法(安全性原因,一般不压缩),以及生成**随机数(\*Server Random\*)**。
接着,返回「**Server Hello**」消息,消息里面有服务器确认的 TLS 版本号,也给出了随机数(Server Random),然后从客户端的密码套件列表选择了一个合适的密码套件。
可以看到,服务端选择的密码套件是 “Cipher Suite: TLS_RSA_WITH_AES_128_GCM_SHA256”。
这个密码套件看起来真让人头晕,好一大串,但是其实它是有固定格式和规范的。基本的形式是「**密钥交换算法 + 签名算法 + 对称加密算法 + 摘要算法**」, 一般 WITH 单词前面有两个单词,第一个单词是约定密钥交换的算法,第二个单词是约定证书的验证算法。比如刚才的密码套件的意思就是:
- 由于 WITH 单词只有一个 RSA,则说明握手时密钥交换算法和签名算法都是使用 RSA;
- 握手后的通信使用 AES 对称算法,密钥长度 128 位,分组模式是 GCM;
- 摘要算法 SHA256 用于消息认证和产生随机数;
就前面这两个客户端和服务端相互「打招呼」的过程,客户端和服务端就已确认了 TLS 版本和使用的密码套件,而且你可能发现客户端和服务端都会各自生成一个随机数,并且还会把随机数传递给对方。
那这个随机数有啥用呢?其实这两个随机数是后续作为生成「会话密钥」的条件,所谓的会话密钥就是数据传输时,所使用的对称加密密钥。
然后,服务端为了证明自己的身份,会发送「**Server Certificate**」给客户端,这个消息里含有数字证书。
随后,服务端发了「**Server Hello Done**」消息,目的是告诉客户端,我已经把该给你的东西都给你了,本次打招呼完毕。
#### TLS 第三次握手
客户端验证完证书后,认为可信则继续往下走。接着,客户端就会生成一个新的**随机数 (pre-master)**,用服务器的 RSA 公钥加密该随机数,通过「**Change Cipher Key Exchange**」消息传给服务端。
服务端收到后,用 RSA 私钥解密,得到客户端发来的随机数 (pre-master)。
至此,**客户端和服务端双方都共享了三个随机数,分别是 Client Random、Server Random、pre-master**。
于是,双方根据已经得到的三个随机数,生成**会话密钥(Master Secret)**,它是对称密钥,用于对后续的 HTTP 请求/响应的数据加解密。
生成完会话密钥后,然后客户端发一个「**Change Cipher Spec**」,告诉服务端开始使用加密方式发送消息。
然后,客户端再发一个「**Encrypted Handshake Message(Finishd)**」消息,把之前所有发送的数据做个摘要,再用会话密钥(master secret)加密一下,让服务器做个验证,验证加密通信是否可用和之前握手信息是否有被中途篡改过。
可以发现,「Change Cipher Spec」之前传输的 TLS 握手数据都是明文,之后都是对称密钥加密的密文。
#### TLS 第四次握手
服务器也是同样的操作,发「**Change Cipher Spec**」和「**Encrypted Handshake Message**」消息,如果双方都验证加密和解密没问题,那么握手正式完成。
最后,就用「会话密钥」加解密 HTTP 请求和响应了。