前言
http 是前端的老朋友了,也是面试常考点,最近看了《图解 http》,结合着 ai 重新理了一遍 https 相关的知识,在此分享。
http 的隐患
众所周知,前端与后端的交互,都需要走接口。绝大部分接口都是 http 协议,随便举一个登录例子:
js
GET /login?user=alice&password=123456 HTTP/1.1
Host: example.com
User-Agent: Chrome
在这个请求发出时,你的信息实际上在整条网络上都是透明的。假如你的网络经过路由器,那么路由器的主人就可以看到你这个请求,也就是能看到你的密码 user=alice&password=123456。
所以国家总会提醒你,不要乱连 wifi,你的信息有可能被监听和泄露。
老前端们过去也总说,前端实际上没有安全性可言。在这个背景下,https 的推出也是理所当然的了。
升级之 https
https 实际上只是在 http 的基础上,增加了一个加密层 TLS,该加密层使用了非对称加密来保证数据不泄露。
非对称加密,区分了公钥和私钥,这里有个很巧妙的数学公式,使信息能任何人都能使用公钥进行加密,但又只能用私钥进行解密。
这个非对称加密的过程相当消耗性能,几乎是原先的数倍甚至数十倍。有没有既可以加密,又保证性能的方案呢?
http 给出的答案是,在第一次通信时,使用非对称加密传递一个密码,随后使用该密码进行对称加密。这样一来,由于密码不会被中间者拦截,所以后续的对称加密也无法被轻易破解。
虽然在控制台上还是会看到正常的信息:
js
POST /api/login HTTP/1.1
Host: example.com
Content-Type: application/json
Content-Length: 42
{"username": "alice", "password": "123456"}
但这只对自己可见。数据在传递过程中完全被加密,抓包只能看到类似如下内容:
js
9a f1 23 8b ... 8e d0
也就是完全转化为了二进制(在抓包软件内会直接显示为十六进制),这样在没有私钥的情况下,就无法将数据还原。
细说加密逻辑
我们来稍微详细了解一下中间的流程。
首先复习下 http 的三次握手:
- 客户端发起链接请求,发送一个
SYN标识 - 服务器确认可以收到客户端消息,发送一个
SYN-ACK标识 - 客户端确认可以收到服务端消息,发送一个
ACK标识
有个很好的比喻:1.喂?听得到吗, 2.我听得到,你听得到我吗 3. 我听得到
https 的加密流程,发生在三次握手之后
目前主流是 TLS 1.3 版本,但旧的 TLS 1.2 版本仍然有部分存量。这两者的加密有所不同,我们分开讨论:
在 TLS 1.2 中:
- 客户端发送 TLS 版本,加密算法,随机数
Client Random - 服务器端发送确认使用的 TLS 版本,加密算法,随机数
Server Random - 客户端校验证书后,再生成一个随机预主密钥
Pre-Master Key,并将Pre-Master Key使用公钥加密后,发送给服务端 - 服务端使用私钥,解开加密,随后双方 根据这三个随机数
Client Random,Server Random,Pre-Master Key生成对话主密钥Master Key - 根据
Master Key生成临时对话秘钥 - 根据临时对话秘钥进行对称加密通信
但这里存在两个问题,1. 基于 rsa 算法的非对称加密,性能消耗还是比较严重 2. 过程繁琐。所以在 TLS 1.3 中对这两点进行了优化。
在 TLS 1.3 中:
- 客户端发送 TLS 版本,加密算法,
客户端 Key Share - 服务端发送确认使用的 TLS 版本,加密算法,
服务端 Key Share - 各自根据
Key Share,使用 ECDHE 算法算出共享密钥 - 使用共享密钥进行对称加密
可以看到,使用 ECDHE 算法,不仅降低了步骤数量,而且由于 ECHDE 所需要的秘钥长度更短,所以性能也更加优秀。