一文搞定HTTP和HTTPS


http 是我们几乎天天都要打交道的东西,相关知识点有点多,所以也有不少面试必问的点,这里做了一些整理,帮且大家树立完整的 http 知识体系,对面试官说 so easy

HTTP 的特点和缺点

特点无连接无状态灵活简单快速

  • 无连接:每一次请求都要连接一次,请求结束就会断掉,不会保持连接
  • 无状态:每一次请求都是独立的,请求结束不会记录连接的任何信息(提起裤子就不认人的意思),减少了网络开销,这是优点也是缺点
  • 灵活:通过 http 协议中头部的Content-Type标记,可以传输任意数据类型的数据对象(文本、图片、视频等等),非常灵活
  • 简单快速:发送请求访问某个资源时,只需传送请求方法和 URL 就可以了,使用简单,正由于 http 协议简单,使得 http 服务器的程序规模小,因而通信速度很快

缺点无状态不安全明文传输队头阻塞

  • 无状态:请求不会记录任何连接信息,没有记忆,就无法区分多个请求发起者身份是不是同一个客户端的,意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大
  • 不安全明文传输可能被窃听不安全,缺少身份认证也可能遭遇伪装,还有缺少报文完整性验证可能遭到篡改
  • 明文传输:报文(header 部分)使用的是明文,直接将信息暴露给了外界,WIFI陷阱就是复用明文传输的特点,诱导你连上热点,然后疯狂抓取你的流量,从而拿到你的敏感信息
  • 队头阻塞:开启长连接(下面有讲)时,只建立一个 TCP 连接,同一时刻只能处理一个请求,那么当请求耗时过长时,其他请求就只能阻塞状态(如何解决下面有讲)

HTTP 报文组成部分

http 报文:由请求报文响应报文组成

请求报文:由请求行请求头空行请求体四部分组成

响应报文:由状态行响应头空行响应体四部分组成

  • 请求行:包含 http 方法,请求地址,http 协议以及版本
  • 请求头/响应头:就是一些 key:value 来告诉服务端我要哪些内容,要注意什么类型等,请求头/响应头每一个字段详解
  • 空行:用来区分首部与实体,因为请求头都是 key:value 的格式,当解析遇到空行时,服务端就知道下一个不再是请求头部分,就该当作请求体来解析了
  • 请求体:请求的参数
  • 状态行:包含 http 协议及版本、数字状态码、状态码英文名称
  • 响应体:服务端返回的数据

HTTP 请求方法(9 种)

HTTP1.0: GETPOSTHEAD

HTTP1.1: PUTPATCHDELETEOPTIONSTRACECONNECT

方法 描述
GET 获取资源
POST 传输资源,通常会造成服务器资源的修改
HEAD 获得报文首部
PUT 更新资源
PATCH 对 PUT 的补充,对已知资源部分更新 菜鸟
DELETE 删除资源
OPTIONS 列出请求资源支持的请求方法,用来跨域请求
TRACE 追踪请求/响应路径,用于测试或诊断
CONNECT 将连接改为管道方式用于代理服务器(隧道代理下面有讲)

GET 和 POST 的区别

  • GET在浏览器回退时是无害的,而POST会再次发起请求
  • GET请求会被浏览器主动缓存,而POST不会,除非手动设置
  • GET请求参数会被安逗保留在浏览器历史记录里,而POST中的参数不会被保留
  • GET请求在URL中传递的参数有长度限制(浏览器限制大小不同),而POST没有限制
  • GET参数通过URL传递,POST放在Request body
  • GET产生的 URL 地址可以被收藏,而POST不可以
  • GET没有POST安全,因为GET请求参数直接暴露在URL上,所以不能用来传递敏感信息
  • GET请求只能进行URL编码,而POST支持多种编码方式
  • 对参数的数据类型,GET只接受ASCII字符,而POST没有限制
  • GET产生一个 TCP 数据包,POST产生两个数据包(Firefox 只发一次)。GET 浏览器把 http header 和 data 一起发出去,响应成功 200,POST 先发送 header,响应 100 continue,再发送 data,响应成功 200

常见 HTTP 状态码

1xx: 指示信息——表示请求已接收,继续处理

2xx: 成功——表示请求已被成功接收

3xx: 重定向——表示要完成请求必须进行进一步操作

4xx: 客户端错误——表示请求有语法错误或请求无法实现

5xx: 服务端错误——表示服务器未能实现合法的请求

常见状态码:

状态码 描述
200 请求成功
206 已完成指定范围的请求(带 Range 头的 GET 请求),场景如 video,audio 播放文件较大,文件分片时
301 永久重定向
302 临时重定向
304 请求资源未修改,可以使用缓存的资源,不用在服务器取
400 请求有语法错误
401 没有权限访问
403 服务器拒绝执行请求,场景如不允许直接访问,只能通过服务器访问时
404 请求资源不存在
500 服务器内部错误,无法完成请求
503 请求未完成,因服务器过载、宕机或维护等

什么是持久连接/长连接

http1.0协议采用的是”请求-应答”模式,当使用普通模式,每个请求/应答客户与服务器都要新建一个连接,完成之后立即断开连接(http协议为无连接的协议)

http1.1版本支持长连接,即请求头添加Connection: Keep-Alive,使用 Keep-Alive 模式(又称持久连接,连接复用)建立一个TCP连接后使客户端到服务端的连接持续有效,可以发送/接受多个http请求/响应,当出现对服务器的后续请求时,Keep-Alive 功能避免了建立或者重新建立连接

1.png

如图:短连接极大的降低了传输效率

长连接优缺点

优点

  • 减少CPU及内存的使用,因为不需要经常建立和关闭连接
  • 支持管道化的请求及响应模式
  • 减少网络堵塞,因为减少了 TCP 请求
  • 减少了后续请求的响应时间,因为不需要等待建立 TCP、握手、挥手、关闭 TCP 的过程
  • 发生错误时,也可在不关闭连接的情况下进行错误提示

缺点

一个长连接建立后,如果一直保持连接,对服务器来说是多么的浪费资源呀,而且长连接时间的长短,直接影响到服务器的并发数

还有就是可能造成队头堵塞(下面有讲),造成信息延迟

如何避免长连接资源浪费?

  • 客户端请求头声明Connection: close,本次通信后就关闭连接
  • 服务端配置:如 Nginx,设置keepalive_timeout设置长连接超时时间,keepalive_requests设置长连接请求次数上限
  • 系统内核参数设置
    • net.ipv4.tcp_keepalive_time = 60,连接闲置 60 秒后,服务端尝试向客户端发送侦测包,判断 TCP 连接状态,如果没有收到 ack 反馈就在
    • net.ipv4.tcp_keepalive_intvl = 10,就在 10 秒后再次尝试发送侦测包,直到收到 ack 反馈,一共会
    • net.ipv4.tcp_keepalive_probes = 5,一共会尝试 5 次,要是都没有收到就关闭这个 TCP 连接了

什么是管线化(管道化)

http1.1在使用长连接的情况下,建立一个连接通道后,连接上消息的传递类似于

请求 1 -> 响应 1 -> 请求 2 -> 响应 2 -> 请求 3 -> 响应 3

管理化连接的消息就变成了类似这样

请求 1 -> 请求 2 -> 请求 3 -> 响应 1 -> 响应 2 -> 响应 3

管线化是在同一个 TCP 连接里发一个请求后不必等其回来就可以继续发请求出去,这可以减少整体的响应时间,但是服务器还是会按照请求的顺序响应请求,所以如果有许多请求,而前面的请求响应很慢,就产生一个著名的问题队头堵塞(下面有讲解决方法)

管线化的特点:

  • 管线化机制通过持久连接完成,在http1.1版本才支持
  • 只有GET请求和HEAD请求才可以进行管线化,而POST有所限制
  • 初次创建连接时不应启动管线化机制,因为服务器不一定支持 http1.1 版本的协议
  • 管线化不会影响响应到来的顺序,如上面的例子所示,响应返回的顺序就是请求的顺序
  • 要求客户端服务端都支持管线化,但并不要求服务端也对响应进行管线化处理,只是要求对于管线化的请求不失败即可
  • 由于上面提到的服务端问题,开户管线化很可能并不会带来大幅度的性能提升,而且很多服务端和代理程序对管线化的支持并不好,因为浏览器(Chrome/Firefox)默认并未开启管线化支持

如何解决 HTTP 的队头阻塞问题

http1.0协议采用的是请求-应答模式,报文必须是一发一收,就形成了一个先进先出的串行队列,没有轻重缓急的优先级,只有入队的先后顺序,排在最前面的请求最先处理,就导致如果队首的请求耗时过长,后面的请求就只能处于阻塞状态,这就是著名的队头阻塞问题。解决如下:

并发连接

因为一个域名允许分配多个长连接,就相当于增加了任务队列,不至于一个队列里的任务阻塞了其他全部任务。以前在 RFC2616 中规定过客户端最多只能并发 2 个连接,但是现实是很多浏览器不按套路出牌,就是遵守这个标准 T_T,所以在 RFC7230 把这个规定取消掉了,现在的浏览器标准中一个域名并发连接可以有6~8个,记住是 6~8 个,不是 6 个(Chrome6 个/Firefox8 个)

如果这个还不能满足你

继续,不要停…

域名分片

一个域名最多可以并发 6~8 个,那咱就多来几个域名

比如 a.baidu.com,b.baidu.com,c.baidu.com,多准备几个二级域名,当我们访问 baidu.com 时,可以让不同的资源从不同的二域名中获取,而它们都指向同一台服务器,这样能够并发更多的长连接了

而在HTTP2.0下,可以一瞬间加载出来很多资源,因为支持多路复用,可以在一个 TCP 连接中发送多个请求

说一下 HTTP 代理

常见的代理有两种:普通代理(中间人代理)隧道代理

普通代理(中间人代理)

1626169261669.jpg

如图:代理服务器相当于一个中间人,一直帮两边传递东西,好可怜~~

不过它可以在中间可以帮我们过滤、缓存、负载均衡(多台服务器共用一台代理情况下)等一些处理

注意,实际场景中客户端和服务器之间可能有多个代理服务器

隧道代理

客户端通过CONNECT方法请求隧道代理创建一个可以到任意目标服务器和端口号的 TCP 连接,创建成功之后隧道代理只做请求和响应数据的转发,中间它不会做任何处理

1626191263809.jpg

为什么需要隧道代理呢?

我们都知道https服务是需要网站有证书的,而代理服务器显然没有,所以浏览器和代理之间无法创建TLS,所以就有了隧道代理,它把浏览器的数据原样透传,这样就实现了通过中间代理和服务端进行 TLS 握手,然后进行加密传输

可能有人会问,那还要代理干嘛,直接请求服务器不是更好吗

代理服务器,到底有什么好处呢?

  • 突破访问限制:如访问一些单位或集团内部资源,或用国外代理服务器(翻墙),就可以上国外网站看片等
  • 安全性更高:上网者可以通过这种方式隐藏自己的 IP,免受攻击。还可以对数据过滤,对非法 IP 限流等
  • 负载均衡:客户端请求先到代理服务器,而代理服务器后面有多少源服务器,IP 是多少,客户端是不知道的。因此,代理服务器收到请求后,通过特定的算法(随机算法、轮询、一致性 hash、LUR(最近最少使用) 算法这里不细说了)把请求分发给不同的源服务器,让各个源服务器负载尽量均衡
  • 缓存代理:将内容缓存到代理服务器(这个下面一节详细说)

代理最常见的请求头

Via

是一个能用首部,由代理服务器添加,适用于正向和反向代理,在请求和响应首部均可出现,这个消息首部可以用来追踪消息转发情况,防止循环请求,还可以识别在请求或响应传递链中消息发送者对于协议的支持能力,详情请看MDN

1
2
3
Via: 1.1 vegur
Via: HTTP/1.1 GWA
Via: 1.0 fred, 1.1 p.example.net

X-Forwarded-For

记录客户端请求的来源 IP,每经过一级代理(匿名代理除外),代理服务器都会把这次请求的来源 IP 追加进去

1
X-Forwarded-For: client,proxy1,proxy2

注意:与服务器直连的代理服务器的 IP 不会被追加进去,该代理可能过 TCP 连接的Remote Address字段获取到与服务器直连的代理服务器 IP

X-Real-IP

一般记录真实发出请求的客户端的 IP,还有X-Forwarded-HostX-Forwarded-Proto分别记录真实发出请求的客户端的域名协议名

代理中客户端 IP 伪造问题以及如何预防?

X-Forwarded-For是可以伪造的,比如一些通过 X-Forwarded-For 获取到客户端 IP 来限制刷票的系统就可以通过伪造该请求头达到刷票的目的,如果客户端请求显示指定了

1
X-Forwarded-For:192.168.1.108

那么服务端收到的这个请求头,第一个 IP 就是伪造的

预防

  1. 在对外 Nginx 服务器上配置
1
2
3
location / {
proxy_set_header X-Forwarded-For $remote_addr
}

这样第一个 IP 就是从TCP连接客户端的 IP,不会读取伪造的

  1. 从右到左遍历X-Forwarded-For的 IP,排除已知代理服务器 IP 和内网 IP,获取到第一个符合条件的 IP 就可以了

正向代理和反向代理

正向代理

工作在客户端的代理为正向代理。使用正向代理的时候,需要在客户端配置需要使用的代理服务器,正向代理对服务端透明。比如抓包工具 Fiddler、Charles 以及访问一些外网网站的代理工具都是正向代理

1626238781500.jpg

正向代理通常用于

  • 缓存
  • 屏蔽某些不健康的网站
  • 通过代理访问原本无法访问的网站
  • 上网认证,对用户访问进行授权

反向代理

工作在服务端的代理称为反向代理。使用反向代理的时候,不需要在客户端进行设置,反向代理对客户端透明。如 Nginx 就是反向代理

1626239283393.jpg

反向代理通常用于负载均衡服务端缓存流量隔离日志金丝雀发布

代理中的长连接

在各个代理和服务器、客户端节点之间是一段一段的 TCP 连接,客户端通过代理访问目标服务器也叫逐段传输,用于逐段传输的请求头叫逐段传输头

逐段传输头会在每一段传输的中间代理中处理掉,不会传给下一个代理

标准的逐段传输头有:Keep-AliveTransfer-EncodingTEConnectionTrailerUpgradeProxy-AuthorizationProxy-Authenticate

Connection 头决定当前事务完成后是否关闭连接,如果该值为 keep-alive,则连接是持久连接不会关闭,使得对同一服务器的请求可以继续在该连接上完成

说一下 HTTP 缓存及缓存代理

关于 http 缓存在上一篇文章里有了详细介绍 (建议收藏)为什么第二次打开页面快?五步吃透前端缓存,让页面飞起

缓存代理就是让代理服务器接管一部分的服务端的 http 缓存,客户端缓存过期之后就近到代理服务器的缓存中获取,代理缓存过期了才请求源服务器,这样流量大的时候能明显降低源服务器的压力

注意响应头字段

  • Cache-Control: 值有public时,表示可以被所有终端缓存,包括代理服务器CDN。值有private时,只能被终端浏览器缓存,CDN、代理等中继服务器都不可以缓存。

HTTPS

HTTPS 是超文本传输安全协议,即HTTP + SSL/TLS。说白了,就是一个加强版的 HTTP

120210715-0.png

HTTP 本文开始讲了,所以我们要理解 HTTPS 的精华,就要先弄清楚这个SSL/TLS

SSL/TLS

一张图让你理解 SSL 和 TLS 的关系

120210715-1.png

如图,TLS 是 SSL 的升级版,而且 TLS1.2 版本以下都已废弃,目前主要用的是TLS 1.2TLS 1.3。而OpenSSL则是开源版本

那么它到底是个啥呢?

浏览器和服务器通信之前会先协商,选出它们都支持的加密套件,用来实现安全的通信。常见加密套件

随便拿出一个加密套件举例,如:RSA-PSK-AES128-GCM-SHA256,就是长这样,代表什么意思呢,我们看图

1626314871054.jpg

  • **RSA**:表示握手时用 RSA 算法交换密钥
  • **PSK**:表示使用 PSK 算法签名
  • AES128-GCM:表示使用 AES256 对称加密算法通信,密钥长度 128,分组模式 GCM。TLS 1.3 中只剩下称加密算法有AESCHACHA20,分组模式只剩下GCMPOLY1305
  • SHA256:表示使用 SHA256 算法验证信息完整性并生成随机数。TLS 1.3 中哈希摘要算法只剩下SHA256SHA384

为什么需要用到这么多算法呢?

为了保证安全,TLS 需要保证信息的:机密性可用性完整性认证性不可否认性,每一种算法都有其特定的用处

HTTPS 中 TLS 的加密算法

为什么说 https 是安全的?
https 一定是安全的吗?(考察 https 中间人劫持,我另一篇有关于详细介绍网络安全)
有什么解决办法?
https 的证书校验过程是怎么样的?
证书校验用到了哪些算法?

对称加密算法

就是加密和解密使用同一个密钥。如AES、DES。加解密过程:

  1. 浏览器给服务器发送一个随机数client-random和一个支持的加密方法列表
  2. 服务器给浏览器返回另一个随机数server-random和双方都支持的加密方法
  3. 然后两者用加密方法将两个随机数混合生成密钥,这就是通信双上加解密的密钥

问题是双方如何安全的传递两个随机数和加密方法,直接传给客户端,那过程中就很可能被窃取,别人就能成功解密拿到数据,往下看

不对称加密算法

就是一对密钥,有公钥(public key)和私钥(private key),其中一个密钥加密后的数据,只能让另一个密钥进行解密。如RSAECDHE。加解密过程:

  1. 浏览器给服务器发送一个随机数client-random和一个支持的加密方法列表
  2. 服务器把另一个随机数server-random加密方法公钥传给浏览器
  3. 然后浏览器用公钥将两个随机数加密,生成密钥,这个密钥只能用私钥解密

使用公钥反推出私钥是非常困难,但不是做不到,随着计算机运算能力提高,非对称密钥至少要2048位才能保证安全性,这就导致性能上要比对称加密要差很多

所以!

TLS 实际用的是两种算法的混合加密通过 非对称加密算法 交换 对称加密算法 的密钥,交换完成后,再使用对称加密进行加解密传输数据。这样就保证了会话的机密性。过程如下

  1. 浏览器给服务器发送一个随机数client-random和一个支持的加密方法列表
  2. 服务器把另一个随机数server-random加密方法公钥传给浏览器
  3. 浏览器又生成另一个随机数pre-random,并用公钥加密后传给服务器
  4. 服务器再用私钥解密,得到pre-random
  5. 浏览器和服务器都将三个随机数用加密方法混合生成最终密钥

这样即便被截持,中间人没有私钥就拿不到pre-random,就无法生成最终密钥。

可又有问题来了,如果一开始就被 DNS 截持,我们拿到的公钥是中间人的,而不是服务器的,数据还是会被窃取,所以数字证书来了,往下看,先简单说一下摘要算法

摘要算法

主要用于保证信息的完整性。常见的MD5 算法散列函数哈希函数都属于这类算法,其特点就是单向性无法反推原文

假如信息被截取,并重新生成了摘要,这时候就判断不出来是否被篡改了,所以需要给摘要也通过会话密钥进行加密,这样就看不到明文信息,保证了安全性,同时也保证了完整性

如何保证数据不被篡改?签名原理和证书?

数字证书(数字签名)

它可以帮我们验证服务器身份。因为如果没有验证的话,就可能被中间人劫持,假如请求被中间人截获,中间人把他自己的公钥给了客户端,客户端收到公钥就把信息发给中间人了,中间人解密拿到数据后,再请求实际服务器,拿到服务器公钥,再把信息发给服务器

这样不知不觉间信息就被人窃取了,所以在结合对称和非对称加密的基础上,又添加了数字证书认证的步骤,让服务器证明自己的身份

数字证书需要向有权威的认证机构(CA)获取授权给服务器。首先,服务器CA机构分别有一对密钥(公钥和私钥),然后是如何生成数字证书的呢?

  • CA 机构通过摘要算法生成服务器公钥的摘要(哈希摘要)
  • CA 机构通过CA 私钥及特定的签名算法加密摘要,生成签名
  • 签名服务器公钥等信息打包放入数字证书,并返回给服务器

服务器配置好证书,以后客户端连接服务器,都先把证书发给客户端验证并获取服务器的公钥。

证书验证流程

  • 使用CA 公钥和声明的签名算法对 CA 中的签名进行解密,得到服务器公钥的摘要内容
  • 再用摘要算法对证书里的服务器公钥生成摘要,再把这个摘要和上一步得到的摘要对比,如果一致说明证书合法,里面的公钥也是正确的,否则就是非法的

证书认证又分为单向认证双向认证

单向认证:服务器发送证书,客户端验证证书
双向认证:服务器和客户端分别提供证书给对方,并互相验证对方的证书

不过大多数 https 服务器都是单向认证,如果服务器需要验证客户端的身份,一般通过用户名、密码、手机验证码等之类的凭证来验证。只有更高级别的要求的系统,比如大额网银转账等,就会提供双向认证的场景,来确保对客户身份提供认证性

HTTPS 连接过程和优化

我们知道了 https 就只是比 http 多了一步 TLS 连接

TLS 连接是怎么回事呢,根据 TLS 版本和密钥交换法不同,过程也不一样,有三种方式

RSA 握手

早期的 TLS 密钥交换法都是使用 RSA 算法,它的握手流程是这样子的

  1. 浏览器给服务器发送一个随机数client-random和一个支持的加密方法列表
  2. 服务器把另一个随机数server-random加密方法公钥传给浏览器
  3. 浏览器又生成另一个随机数pre-random,并用公钥加密后传给服务器
  4. 服务器再用私钥解密,得到pre-random,此时浏览器和服务器都得到三个随机数了,各自将三个随机数用加密方法混合生成最终密钥

然后开始通信

TLS 1.2 版

TLS 1.2版的用的是ECDHE密钥交换法,看图

1626337585114.jpg

  1. 浏览器给服务器发送一个随机数client-random、TLS 版本和一个支持的加密方法列表
  2. 服务器生成一个椭圆曲线参数server-params、随机数server-random加密方法证书等传给浏览器
  3. 浏览器又生成椭圆曲线参数client-params,握手数据摘要等信息传给服务器
  4. 服务器再返回摘要给浏览器确认应答

这个版本不再生成椭圆曲线参数cliend-paramsserver-params,而是在服务器和浏览器两边都得到server-paramsclient-params之后,就用 ECDHE 算法直接算出pre-random,这就两边都有了三个随机数,然后各自再将三个随机加密混合生成最终密钥

TLS 1.3 版

在 TLS1.3 版本中废弃了 RSA 算法,因为 RSA 算法可能泄露私钥导致历史报文全部被破解,而 ECDHE 算法每次握手都会生成临时的密钥,所以就算私钥被破解,也只能破解一条报文,而不会对之前的历史信息产生影响,,所以在 TLS 1.3 中彻底取代了 RSA。目前主流都是用ECDHE算法来做密钥交换的

TLS1.3 版本中握手过程是这样子的
1626443582577.jpg

  1. 浏览器生成client-params、和client-random、TLS 版本和加密方法列表发送给服务器
  2. 服务器返回server-paramsserver-random加密方法证书摘要等传给浏览器
  3. 浏览器确认应答,返回握手数据摘要等信息传给服务器

简单说就是简化了握手过程,只有三步,把原来的两个 RTT 打包成一个发送了,所以减少了传输次数。这种握手方式也叫1-RTT握手

这种握手方还有优化空间吗?

有的,用会话复用

会话复用

会话复用有两种方式:Session IDSession Ticket

**Session ID**:就是客户端和服务器首次连接手各自保存会话 ID,并存储会话密钥,下次再连接时,客户端发送 ID 过来,服务器这边再查找 ID,如果找到了就直接复用会话,密钥也不用重新生成

可是这样的话,在客户端数量庞大的时候,对服务器的存储压力可就大了

所以出来了第二种方式 **Session Ticket**:就是双方连接成功后服务器加密会话信息,用 Session Ticket 消息发给客户端存储起来,下次再连接时就把这个 Session Ticket 解密,验证有没有过期,如果没有过期就复用会话。原理就是把存储压力分给客户端。

这样就万无一失了吗?

No,这样也存在安全问题。因为每次要用一个固定的密钥来解密 Session Ticket,一旦密钥被窃取,那所有历史记录也就被破解了,所以只能尽量避免这种问题定期更换密钥。毕竟节省了不少生成会话密钥和这些算法的耗时,性能还是提升了嘛

那刚说了1-RTT,那能不能优化到0-RTT

还真可以,做法就是发送 Session Ticket 的时候带上应用数据,不用等服务端确认。这种方式被称为PSK(Pre-Shared Key)

这样万无一失了吗?

尴了个尬,还是不行。这 PSK 要是被窃取,人家不断向服务器重发,就直接增加了服务器被攻击的风险

虽然不是绝对安全,但是现行架构下最安全的解决文案了,大大增加了中间人的攻击成本

HTTPS 优缺点

优点

  • 内容加密,中间无法查看原始内容
  • 身份认证,保证用户访问正确。如访问百度,即使 DNS 被劫持到第三方站点,也会提醒用户没有访问百度服务,可能被劫持
  • 数据完整性,防止内容被第三方冒充或篡改
  • 虽然不是绝对安全,但是现行架构下最安全的解决文案了,大大增加了中间人的攻击成本

缺点

  • 要钱,功能越强大的证书费用越贵
  • 证书需要绑定 IP,不能在同一个 IP 上绑定多个域名
  • https 双方加解密,耗费更多服务器资源
  • https 握手更耗时,降低一定用户访问速度(优化好就不是缺点了)

HTTP 和 HTTPS 的区别

  • HTTP 是明文传输,不安全的,HTTPS 是加密传输,安全的多
  • HTTP 标准端口是80,HTTPS 标准端口是443
  • HTTP 不用认证证书免费,HTTPS 需要认证证书要钱
  • 连接方式不同,HTTP 三次握手,HTTPS 中 TLS1.2 版本 7 次,TLS1.3 版本 6 次
  • HTTP 在 OSI 网络模型中是在应用层,而 HTTPS 的 TLS 是在传输层
  • HTTP 是无状态的,HTTPS 是有状态

HTTPS 的性能优化

访问速度优化

  1. 会话复用,上面说了,复用 session 可以减少 CPU 消耗,因为不需要进行非对称密钥交换的计算。可以提升访问速度,不需要进行完全握手阶段二,节省了一个 RTT 和计算耗时。
  2. 使用 SPDY 或者 HTTP2。SPDY 最大的特性就是多路复用,能将多个 HTTP 请求在同一个连接上一起发出去,不像目前的 HTTP 协议一样,只能串行地逐个发送请求。Pipeline 虽然支持多个请求一起发送,但是接收时依然得按照顺序接收,本质上无法解决并发的问题。HTTP2 支持多路复用,有同样的效果。
  3. 设置HSTS,服务端返回一个 HSTS 的 http header,浏览器获取到 HSTS 头部之后,在一段时间内,不管用户输入www.baidu.com还是http:\/\/www.baidu.com ,都会默认将请求内部跳转成 https://www.baidu.com。Chrome, firefox, ie 都支持了 HSTS。
  4. Nginx设置Ocsp stapling。Ocsp 全称在线证书状态检查协议 (rfc6960),用来向 CA 站点查询证书状态,比如是否撤销。通常情况下,浏览器使用 OCSP 协议发起查询请求,CA 返回证书状态内容,然后浏览器接受证书是否可信的状态。这个过程非常消耗时间,因为 CA 站点有可能在国外,网络不稳定,RTT 也比较大。如果不需要查询则可节约时间。
  5. False start。简单概括 False start 的原理就是在 clientkeyexchange 发出时将应用层数据一起发出来,能够节省一个 RTT。

计算性能优化

  1. 优先使用 ECC 椭圆加密算术
  2. 使用最新版的 OpenSSL
  3. TLS 远程代理计算
  4. 硬件加速方案

HTTP 版本

1991 年 HTTP 0.9 版,只有一个 GET,而且只支持纯文本内容,早已过时就不讲了

HTTP 1.0(1996 年)

  • 任意数据类型都可以发送
  • 有 GET、POST、HEAD 三种方法
  • 无法复用 TCP 连接(长连接)
  • 有丰富的请求响应头信息。以 header 中的Last-Modified/If-Modified-SinceExpires作为缓存标识

HTTP 1.1(1997 年)

  • 引入更多的请求方法类型PUTPATCHDELETEOPTIONSTRACECONNECT
  • 引入长连接,就是 TCP 连接默认不关闭,可以被多个请求复用,通过请求头 connection:keep-alive 设置
  • 引入管道连接机制,可以在同一 TCP 连接里,同时发送多个请求
  • 强化了缓存管理和控制Cache-ControlETag/If-None-Match
  • 支持分块响应,断点续传,利于大文件传输,能过请求头中的Range实现
  • 使用了虚拟网络,在一台物理服务器上可以存在多个虚拟主机,并且共享一个 IP 地址

缺点:主要是连接缓慢,服务器只能按顺序响应,如果某个请求花了很长时间,就会出现请求队头阻塞

虽然出了很多优化技巧:为了增加并发请求,做域名拆分、资源合并、精灵图、资源预取…等等

最终为了推进从协议上进行优化,Google 跳出来,推出SPDY协议

SPDY(2009 年)

SPDY(读作“SPeeDY”)是 Google 开发的基于 TCP 的会话层协议

主要通过帧、多路复用、请求优先级、HTTP 报头压缩、服务器推送以最小化网络延迟,提升网络速度,优化用户的网络使用体验

原理是在 SSL 层上增加一个 SPDY 会话层,以在一个 TCP 连接中实现并发流。通常的 HTTP GET 和 POST 格式仍然是一样的,然而 SPDY 为编码和传输数据设计了一个新的帧格式。因为流是双向的,所以可以在客户端和服务端启动

虽然诞生后很快被所有主流浏览器所采用,并且服务器和代理也提供了支持,但是 SPDY 核心人员后来都参加到 HTTP 2.0 开发中去了,自 HTTP2.0 开发完成就不再支持 SPDY 协议了,并在 Chrome 51 中删掉了 SPDY 的支持

HTTP 2.0(2015 年)

说出 http2 中至少三个新特性?

  • 使用新的二进制协议,不再是纯文本,避免文本歧义,缩小了请求体积
  • 多路复用,同域名下所有通信都是在单链接(双向数据流)完成,提高连接的复用率,在拥塞控制方面有更好的能力提升
  • 使用HPACK算法将头部压缩,用哈夫曼编码建立索表,传送索引大大节约了带宽
  • 允许服务端主动推送数据给客户端
  • 增加了安全性,使用 HTTP 2.0,要求必须至少 TLS 1.2
  • 使用虚拟的流传输消息,解决了应用层的队头阻塞问题

缺点

  • TCP 以及 TCP+TLS 建立连接的延时,HTTP2 使用 TCP 协议来传输的,而如果使用 HTTPS 的话,还需要 TLS 协议进行安全传输,而使用 TLS 也需要一个握手过程,在传输数据之前,导致我们花掉 3~4 个 RTT
  • TCP 的队头阻塞并没有彻底解决。在 HTTP2 中,多个请求跑在一个 TCP 管道中,但当 HTTP2 出现丢包时,整个 TCP 都要开始等待重传,那么就会阻塞该 TCP 连接中的所有请求

SPDY 和 HTTP2 的区别

  • 头部压缩算法,SPDY 是通用的deflate算法,HTTP2 是专门为压缩头部设计的HPACK算法
  • SPDY 必须在TLS上运行,HTTP2 可在TCP上直接使用,因为增加了 HTTP1.1 的 Upgrade 机制
  • SPDY 更加完善的协议商讨和确认流程
  • SPDY 更加完善的 Server Push 流程
  • SPDY 增加控制帧的种类,并对帧的格式考虑的更细致

HTTP1 和 HTTP2

  • HTTP2 是一个二进制协议,HTTP1 是超文本协议,传输的内容都不是一样的
  • HTTP2 报头压缩,可以使用 HPACK 进行头部压缩,HTTP1 则不论什么请求都会发送
  • HTTP2服务端推送(Server push),允许服务器预先将网页所需要的资源 push 到浏览器的内存当中
  • HTTP2 遵循多路复用,代替同一域名下的内容,只建立一次连接,HTTP1.x 不是,对域名有 6~8 个连接限制
  • HTTP2 引入二进制数据帧的概念,其中帧对数据进行顺序标识,这样浏览器收到数据之后,就可以按照序列对数据进行合并,而不会出现合并后数据错乱的情况,同样是因为有了序列,服务器就可以并行的传输数据,这就是流所做的事情。HTTP2 对同一域名下所有请求都是基于流的,也就是说同一域名下不管访问多少文件,只建立一次连接

HTTP 3.0/QUIC

由于 HTTP 2.0 依赖于 TCP,TCP 有什么问题那 HTTP2 就会有什么问题。最主要的还是队头阻塞,在应用层的问题解决了,可是在 TCP 协议层的队头阻塞还没有解决。

TCP 在丢包的时候会进行重传,前面有一个包没收到,就只能把后面的包放到缓冲区,应用层是无法取数据的,也就是说 HTTP2 的多路复用并行性对于 TCP 的丢失恢复机制不管用,因此丢失或重新排序的数据都会导致交互挂掉

为了解决这个问题,Google 又发明了QUIC协议

并在 2018 年 11 月将 QUIC 正式改名为HTTP 3.0

特点

  • 在传输层直接干掉 TCP,用UDP替代
  • 实现了一套新的拥塞控制算法,彻底解决 TCP 中队头阻塞的问题
  • 实现了类似 TCP 的流量控制、传输可靠性的功能。虽然 UDP 不提供可靠性的传输,但 QUIC 在 UDP 的基础之上增加了一层来保证数据可靠性传输。它提供了数据包重传、拥塞控制以及其他一些 TCP 中存在的特性
  • 实现了快速握手功能。由于 QUIC 是基于 UDP 的,所以 QUIC 可以实现使用 0-RTT 或者 1-RTT 来建立连接,这意味着 QUIC 可以用最快的速度来发送和接收数据。
  • 集成了 TLS 加密功能。目前 QUIC 使用的是 TLS1.3

文章作者: 沐华
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 沐华 !