介绍
HTTP 缓存
HTTP 缓存有助于增加响应速度、减少带宽消耗。
缓存控制 ── cache control
HTTP 中有两个控制缓存的响应头
- pragma (弃用)
- cache control
max-age
上图中 cache-control: max-age=31536000
表示资源大概率一年不变。这样 CDN 和浏览器就会倾向于长期存储这个资源。
no-cache
对于一些可能改变静态资源(如 html)会使用 cache-control: no-cache 进行缓存控制。其含义表示每次请求资源都询问服务器,服务器说资源没变,那浏览器就会从 CDN 或者浏览器缓冲中取文件,省去了从服务器下载的过程。
no-store
容易与 no-cache 含义搞混。no-cache 表示缓存,但不一定使用;no-store 表示不缓存,每次都问服务器要。
HTTPS (HTTP 加密)
HTTPS 是 HTTP 的非对称加密协议。
💡加密算法参考这篇文章: https://blog.csdn.net/LawssssCat/article/details/104926571
所谓非对称加密指:
- 一个对钥匙分公钥、私钥
- 公钥大家都知道,发信息者使用公钥将信息加密,该加密结果只能通过私钥解密
- 私钥只有接收者知道,因为发送的信息只有私钥才能解开,因此可以认为只有拥有密钥的接收者才知道信息的内容
💡配置 HTTPS 看这篇文章: https://lawsssscat.blog.csdn.net/article/details/127128683
简单来说使用 HTTPS 通信可以起到两个作用:
- 加密通信: 通信传输过程中,第三方无法查看传输内容
- 防伪: 第三方无法冒认服务器与我们通信
HTTPS 握手流程
具体抓包分析看这里: https://www.bilibili.com/video/BV1KY411x7Jp/ by 技术蛋老师
SSL、TLS/1.2
SSL、TLS 都是加密安全协议。SSL 是 TLS 的前身,但由于 SSL 历史悠久,大家都习惯将 HTTPS 使用的协议称为 SSL 协议。
随着协议的发展,TLS 已经和 SSL 大不相同,尤其是 TLS/1.2 升级到 TLS/1.3 之后。
TLS/1.2 核心算法有两个:RSA(Rivest-Shamir-Adleman)、DH(Diffie-Hellman)
从通信流程上看,RSA 算法只需要服务端静态的保存公钥、私钥既可实现加密通信。
⚠️但是,这是有风险的: 如果私钥被破解了,并且以前通信的内容被长期保存了下来。那么,攻击方可以通过被破解的密钥解密以前通讯的全部内容!
💡密码学中,将这种静态 RSA 算法称为 “存在前向保密(前向安全)问题”
为此,DH 算法的设计是客户端、服务端都存有「计算」私钥。它们通过非对称加,先交换参数(包含随机值),算出出统一的「通信」私钥,再用这「通信」私钥进行对称加密通信。
同时,要求客户端的「计算」私钥经常改变。这样,即使服务端的「计算」私钥被破解了,也无法解密出历史通信信息。即使客户端某一时间段的「计算」私钥也被破解了,那也只能解密出那一段事件的历史通信,而无法知道全部的历史通信。
不幸的是,TLS/1.2 中允许 RSA、DH 算法一直使用相同的密钥通信。这样,无论 RSA 算法还是 DH 算法都会存在上述的前向保密(前向安全)问题。因此,这种静态的 RSA 和 DH 密钥交换算法在 TLS/1.3 中就被移除了。
TLS/1.3
禁止静态密钥交换
同上
移除较弱密码套件
TLS/1.3 的升级除了有上述的禁止静态密钥交换外,还废弃很多 DH 算法中比较弱的参数组合,避免 TLS 降级。
这是因为 TLS 握手开始是明文的,且最终协议是由客户端决定的。因此,黑客可以伪造客户端的决定,要求服务端使用尽量低的 https 加密方式(TLS 降级,如降到 512bit ssl 就很容易破解)。
由于废弃很多弱参数组合,且原先的密码套件命名规则不好用,因此,TLS/1.3 中使用了新的密码套件命名规则:
- TLS/1.2 中的命名规则和密码套件
密码套件有37种(选择困难。也有可能出现客户端选好了,服务端不支持的尴尬局面)
- TLS/1.3 中的命名规则和密码套件
密码套件只有5种(清爽)
优化通信流程
另外,TLS 1.3 在客户端发送请求时就会把协商参数发出,这样减少了一次通信,使用 1-RTT 就能生成对称加密的私钥。
优化加密填充模式
解决 PKCS#1 v1.5 漏洞,使用 PSS 方式进行填充。
参考: https://www.bilibili.com/video/BV12X4y197Pr/
HTTP 版本
HTTP/1.1
HTTP/1.1 有以下问题
HTTP 队头阻塞
HTTP/1.1 中,TCP 三次握手后,会建立 keep-alive(持久链接)的 TCP 连接。请求和响应都可以放在这个连接中。也只有连接建立后,浏览器才正式向服务器发送资源请求。
浏览器接收到 html 内容后,才依次请求 html 中需要的 css、js 等文件。
但是,如果只有一个 TCP 连接,那么在前有一个请求没有收到响应时,后面的文件也没法接收。这就是 HTTP 队头阻塞,如下图:
为此,浏览器通常用多个 TCP 连接同时访问服务器。(但是,如果连接开太多,又容易被利用来进行 DDoS 攻击。因此,浏览器通常只请求建立 6 个连接。)
但是,用多连接也没法避免重要的资源来的比较慢,导致页面无法渲染(如:CSS)
解决思路:
- 管线化技术 ── ❌难以维护
管线化技术让单个连接可以发送多个请求。这样避免了由于没有响应,浏览器就不继续请求的情况。- 但由于网络中存在丢包问题,没法确定响应是属于哪个请求的,所以在浏览器中没得到推广。
- (题外话)相反,管道技术在 nodejs 中从本地读文件时倒是很喜欢用。
- 将多个资源合并成一个响应 ── ✔️封装图片处理工具包,可行
这样就只需要发送一个请求,从而避免了多请求阻塞
- data urls ── ✔️配合包管理器,可行
- 将图片进行 base64 编码,嵌入 html 中。这样就避免了专门请求这个图片。
- 将 css、js 整合到 html 中
- 设置多个资源服务器域名 ── ❌浪费资源
利用了浏览器可以同时对多个不同域名发送请求的机制,将资源请求分布到多个资源服务器域名上。这样,就算开发同意,运维同意,老版也是不会同意的。
使用 HTTPS 后,握手成本翻倍
不管 HTTPS 使用 TLS/1.2 还是 TLS/1.3,都要增加握手负担。
最直接的影响是会提高丢包概率,进一步导致 HTTP 队头阻塞。
TCP 慢启动
为了不造成网络拥堵和不清楚网络情况,浏览器开始只会发送较小量的 TCP 数据段,到后面才慢慢增加。这导致打开新页面时刷新速度慢。
HTTP 固定开销
HTTP 请求头、Cookie 很多信息是固定不变的,但每次传输都要携带,也是明文的没进行压缩。
HTTP/2
下面是 HTTP/2 的优化
多路复用
和管线化技术类似,允许一个连接发送多个请求和响应。不同的是对每个报文用帧划分,并对帧进行标识(流标识)
这样,即使排前面的数据因为网络原因比较晚收到,浏览器也可以根据标识把数据放到它计划好的地方。
报文压缩
在 HTTP/1.1 中,只压缩报文主体,而不压缩报文首部。在 HTTP/2 中就通过 HPACK 算法对报文首部也进行也压缩。
HPACK 简单的说就是:
- 规定更短的请求头字符
- 服务器对 Cookie 等信息进行缓存
- 将报文从 ASCII 编码直接转换成二进制来传输
服务器推送 🔥
允许服务器主动通过连接给浏览器发消息。
能提高资源的请求效率,也会有安全风险:通过数量不对称的响应来制作放大 DDoS 攻击。
websocket
产品经理两眼放光: 什么聊天室、协同编辑、…都能通过浏览器实现了!
HTTP/3
HTTP/2 有很棒的设计,但也有严重的问题。于是,没过多久就推出 HTTP/3 来解决这些问题。
TCP 队头阻塞
前面说了,在 HTTP/1.1 的请求中,以报文为单位收发请求。这样的话,在的一个 TCP 连接中,可能因为某个 HTTP 报文的缺失而阻塞了后序的请求。
在 HTTP/2 中虽然把请求单位改为帧,放在 TCP 中进行请求。这样虽然避免了 HTTP 队头阻塞,但还是没法避免 TCP 队头阻塞问题。
最简单的方法就是将 TCP 的段也改成帧那样可以定位数据位置。但这没法实现,因为 TCP 协议是在系统中实现的,浏览器没法要求系统更新。
于是有了 HTTP/3 协议。HTTP/3 通过 UDP 和一个新设计的协议 QUIC,将 TLS 和 TCP 的功能进行了整合,实现了应用层和传输层都以以帧形式传递数据。
具体 QUIC 做了啥,看 https://www.bilibili.com/video/BV1vv4y1U77y/
引用链接
- 什么是HTTP缓存? by 技术蛋老师
- HTTPS是什么?加密原理和证书。SSL/TLS握手过程 by 技术蛋老师
- DH算法 | 迪菲-赫尔曼Diffie–Hellman 密钥交换 by 技术蛋老师
- HTTP/1.1,HTTP/2和HTTP/3的区别 by 技术蛋老师