学习自极客时间《趣谈网络协议》 作者:刘超
1. HTTP协议
1.1 HTTP 请求的准备
我们在浏览器上输入的网址,比如https://www.baidu.com/, 就是一个URL,也叫做统一资源定位符。之所以叫统一,是因为它是有格式的。HTTP 称为协议,www.baidu.com 是一个域名,表示互联网上的一个位置。正是因为这个东西是统一的,所以当你把这样一个字符串输入到浏览器的框里的时候,浏览器才知道如何进行统一处理。
浏览器将域名发送给DNS服务器,然后DNS将域名解析为IP地址,HTTP 是基于 TCP 协议的,先建立 TCP 连接,目前使用的 HTTP 协议大部分都是 1.1。在 1.1 的协议里面,默认是开启了 Keep-Alive 的,这样建立的 TCP 连接,就可以在多次请求中复用。
1.2 HTTP 请求的构建
建立了连接后,就可以发送http请求。
请求的格式如下:
(1)请求行
方法
- GET: GET 就是去服务器获取一些资源。对于访问网页来讲,要获取的资源往往是一个页面。其实也有很多其他的格式,比如说返回一个 JSON 字符串,到底要返回什么,是由服务器端的实现决定的。
- POST:它需要主动告诉服务端一些信息,而非获取。要告诉服务端什么呢?一般会放在正文里面。正文可以有各种各样的格式。常见的格式也是 JSON。
- PUT: 向指定资源位置上传最新内容。但是,HTTP 的服务器往往是不允许上传文件的,所以 PUT 和 POST 就都变成了要传给服务器东西的方法。
在实际使用过程中,这两者还会有稍许的区别。POST 往往是用来创建一个资源的,而 PUT 往往是用来修改一个资源的。 - DELETE: 这个顾名思义就是用来删除资源的。
URL就是类似 https://www.baidu.com/ 的统一资源定位符
版本为http版本如1.1
(2)首部字段
首部是 key value,通过冒号分隔。这里面,往往保存了一些非常重要的字段。
- Accept-Charset: 表示客户端可以接受的字符集。防止传过来的是另外的字符集,从而导致出现乱码。
- Content-Type: 指正文的格式。例如,我们进行 POST 的请求,如果正文是 JSON,那么我们就应该将这个值设置为 JSON。
- Cache-control: 用来控制缓存的。当客户端发送的请求中包含 max-age 指令时,如果判定缓存层中,资源的缓存时间数值比指定时间的数值小,那么客户端可以接受缓存的资源;当指定 max-age 值为 0,那么缓存层通常需要将请求转发给应用集群。
- If-Modified-Since: 也是一个关于缓存的。也就是说,如果服务器的资源在某个时间之后更新了,那么客户端就应该下载最新的资源;如果没有更新,服务端会返回“304 Not Modified”的响应,那客户端就不用下载了,也会节省带宽。
为什么要使用缓存
- 减少相应延迟:因为请求从缓存服务器(离客户端更近)而不是源服务器被相应,这个过程耗时更少,让web服务器看上去相应更快;
- 减少网络带宽消耗:当副本被重用时会减低客户端的带宽消耗;客户可以节省带宽费用,控制带宽的需求的增长并更易于管理。
对于这种高并发场景下的系统,在真正的业务逻辑之前,都需要有个接入层,将这些静态资源的请求拦在最外面。
参考文献: https://zhuanlan.zhihu.com/p/90507417
1.3 HTTP 请求的发送
HTTP 协议是基于 TCP 协议的,所以它使用面向连接的方式发送请求,通过 stream 二进制流的方式传给对方。当然,到了 TCP 层,它会把二进制流变成一个个报文段发送给服务器。
- TCP层:在发送给每个报文段的时候,都需要对方有一个回应 ACK,来保证报文可靠地到达了对方。如果没有回应,那么 TCP 这一层会进行重新传输,直到可以到达。在tcp层报可能被传送多次,但对于http层是透明的。
TCP 层发送每一个报文的时候,都需要加上自己的地址(即源地址)和它想要去的地方(即目标地址),将这两个信息放到 IP 头里面,交给 IP 层进行传输。 - IP层: IP 层需要查看目标地址和自己是否是在同一个局域网。如果是,就发送 ARP 协议来请求这个目标地址对应的 MAC 地址,然后将源 MAC 和目标 MAC 放入 MAC 头,发送出去即可;如果不在同一个局域网,就需要发送到网关,还要需要发送 ARP 协议,来获取网关的 MAC 地址,然后将源 MAC 和网关 MAC 放入 MAC 头,发送出去。
- 链路层: 网关收到包发现 MAC 符合,取出目标 IP 地址,根据路由协议找到下一跳的路由器,获取下一跳路由器的 MAC 地址,将包发给下一跳路由器。这样路由器一跳一跳终于到达目标的局域网。这个时候,最后一跳的路由器能够发现,目标地址就在自己的某一个出口的局域网上。于是,在这个局域网上发送 ARP,获得这个目标地址的 MAC 地址,将包发出去。
目标的机器发现 MAC 地址符合,就将包收起来;发现 IP 地址符合,根据 IP 头中协议项,知道自己上一层是 TCP 协议,于是解析 TCP 的头,里面有序列号,需要看一看这个序列包是不是我要的,如果是就放入缓存中然后返回一个 ACK,如果不是就丢弃。 - TCP 头里面还有端口号,HTTP 的服务器正在监听这个端口号。于是,目标机器自然知道是 HTTP 服务器这个进程想要这个包,于是将包发给 HTTP 服务器。HTTP 服务器的进程看到,原来这个请求是要访问一个网页,于是就把这个网页发给客户端。
1.4 HTTP 返回的构建
HTTP 的返回报文也是有一定格式的。这也是基于 HTTP 1.1 的。
(1) 状态行
- 版本: HTTP协议的版本号
- 状态码:
(2)首部
- Retry-After: 告诉客户端应该在多长时间以后再次尝试一下。“503 错误”是说“服务暂时不再和这个值配合使用”。
- Content-Type: 指正文的格式。
HTTP 响应的发送和请求发送类似。
2. HTTP 2.0
HTTP 1.1 在应用层以纯文本的形式进行通信。每次通信都要带完整的 HTTP 的头,而且不考虑 pipeline 模式的话,每次的过程总是像上面描述的那样一去一回。这样在实时性、并发性上都存在问题。HTTP 2.0 会对 HTTP 的头进行一定的压缩,将原来每次都要携带的大量 key value 在两端建立一个索引表,对相同的头只发送索引表中的索引。
pipeLining 管道
持久连接解决了连接复用问题,但还是存在着一个问题:在一个 TCP 连接中,同一时间只能够发送一个请求,并且需要等响应完成才能够发送第二个请求。
因此 HTTP/1.1 制订了 PipeLining 管道,通过这个管道,浏览器的多个请求可以同时发到服务器,但是服务器的响应只能够一个接着一个的返回 ( 但各大浏览器有些不支持/默认关闭,因此这功能可以说是鸡肋)。
因为每一条连接同时只能够返回一个响应,因此浏览器为了改善这种情况,会同时开启4~8个 TCP 连接进行发送请求。
参考文章 : https://cloud.tencent.com/developer/article/1464264另外,HTTP 2.0 协议将一个 TCP 的连接中,切分成多个流,每个流都有自己的 ID,而且流可以是客户端发往服务端,也可以是服务端发往客户端。它其实只是一个虚拟的通道。流是有优先级的。
HTTP 2.0 还将所有的传输信息分割为更小的消息和帧,并对它们采用二进制格式编码。常见的帧有 Header 帧,用于传输 Header 内容,并且会开启一个新的流。再就是 Data 帧,用来传输正文实体。多个 Data 帧属于同一个流。
通过这两种机制,HTTP 2.0 的客户端可以将多个请求分到不同的流中,然后将请求内容拆成帧,进行二进制传输。这些帧可以打散乱序发送, 然后根据每个帧首部的流标识符重新组装,并且可以根据优先级,决定优先处理哪个流的数据。
发送多个请求的时候,使用 HTTP 1.1 就是串行的,但是如果使用 HTTP 2.0,就可以在一个连接里,客户端和服务端都可以同时发送多个请求或回应,而且不用按照顺序一对一对应。
HTTP 2.0 成功解决了 HTTP 1.1 的队首阻塞问题,同时,也不需要通过 HTTP 1.x 的 pipeline 机制用多条 TCP 连接来实现并行请求与响应;减少了 TCP 连接数对服务器性能的影响。
3. QUIC 协议
QUIC(全称 Quick UDP Internet Connections,快速 UDP 互联网连接)是 Google 提出的一种基于 UDP 改进的通信协议,其目的是降低网络通信的延迟,提供更好的用户互动体验。QUIC 在应用层上,会自己实现快速连接建立、减少重传时延,自适应拥塞控制,
因为 HTTP 2.0 也是基于 TCP 协议的,TCP 协议在处理包时是有严格顺序的。当其中一个数据包遇到问题,TCP 连接需要等待这个包完成重传之后才能继续进行。虽然 HTTP 2.0 通过多个 stream,使得逻辑上一个 TCP 连接上的并行内容,进行多路数据的传输,然而这中间并没有关联的数据。一前一后,前面 stream 2 的帧没有收到,后面 stream 1 的帧也会因此阻塞。
机制一. 自定义连接机制
一条 TCP 连接是由四元组标识的,分别是源 IP、源端口、目的 IP、目的端口。一旦一个元素发生变化时,就需要断开重连,重新连接。
但是基于 UDP,就可以在 QUIC 自己的逻辑里面维护连接的机制,不再以四元组标识,而是以一个 64 位的随机数作为 ID 来标识,而且 UDP 是无连接的,所以当 IP 或者端口变化的时候,只要 ID 不变,就不需要重新建立连接。
机制二. 自定义重传机制
TCP 为了保证可靠性,通过使用序号和应答机制,来解决顺序问题和丢包问题。任何一个序号的包发过去,都要在一定的时间内得到应答,否则一旦超时,就会重发这个序号的包。利用自适应重传算法,通过采样往返时间 RTT 不断调整超时时间。
- QUIC 也有个序列号,是递增的。任何一个序列号的包只发送一次,下次就要加一了。例如,发送一个包,序号是 100,发现没有返回;再次发送的时候,序号就是 101 了;如果返回的 ACK 100,就是对第一个包的响应。如果返回 ACK 101 就是对第二个包的响应,RTT 计算相对准确。
- QUIC 既然是面向连接的,也就像 TCP 一样,是一个数据流,发送的数据在这个数据流里面有个偏移量 offset,可以通过 offset 查看数据发送到了哪里,这样只要这个 offset 的包没有来,就要重发;如果来了,按照 offset 拼接,还是能够拼成一个流。
机制三. 无阻塞的多路复用
有了自定义的连接和重传机制,我们就可以解决上面 HTTP 2.0 的多路复用问题。
同 HTTP 2.0 一样,同一条 QUIC 连接上可以创建多个 stream,来发送多个 HTTP 请求。但是,QUIC 是基于 UDP 的,一个连接上的多个 stream 之间没有依赖。这样,假如 stream2 丢了一个 UDP 包,后面跟着 stream3 的一个 UDP 包,虽然 stream2 的那个包需要重传,但是 stream3 的包无需等待,就可以发给用户。
机制四. 自定义流量控制
TCP 的流量控制是通过滑动窗口协议。QUIC 的流量控制也是通过 window_update,来告诉对端它可以接受的字节数。但是 QUIC 的窗口是适应自己的多路复用机制的,不但在一个连接上控制窗口,还在一个连接中的每个 stream 控制窗口。
在 TCP 协议中,接收端的窗口的起始点是下一个要接收并且 ACK 的包,即便后来的包都到了,放在缓存里面,窗口也不能右移,因为 TCP 的 ACK 机制是基于序列号的累计应答,一旦 ACK 了一个系列号,就说明前面的都到了,所以只要前面的没到,后面的到了也不能 ACK,就会导致后面的到了,也有可能超时重传,浪费带宽。
QUIC 的 ACK 是基于 offset 的,每个 offset 的包来了,进了缓存,就可以应答,应答后就不会重发,中间的空挡会等待到来或者重发即可,而窗口的起始位置为当前收到的最大 offset,从这个 offset 到当前的 stream 所能容纳的最大缓存,是真正的窗口大小。显然,这样更加准确。
详细的可以上网或者看看文档啥的。。。
4. HTTPS 协议
4.1 什么是 HTTPS?
HTTPS协议 = HTTP协议 + SSL/TLS协议,在HTTPS数据传输的过程中,需要用SSL/TLS对数据进行加密和解密,需要用HTTP对加密后的数据进行传输,由此可以看出HTTPS是由HTTP和SSL/TLS一起合作完成的。
- SSL的全称是Secure Sockets Layer,即安全套接层协议,是为网络通信提供安全及数据完整性的一种安全协议。SSL协议在1994年被Netscape发明,后来各个浏览器均支持SSL,其最新的版本是3.0
- TLS的全称是Transport Layer Security,即安全传输层协议,最新版本的TLS(Transport Layer Security,传输层安全协议)是IETF(Internet Engineering Task Force,Internet工程任务组)制定的一种新的协议,它建立在SSL 3.0协议规范之上,是SSL 3.0的后续版本。在TLS与SSL3.0之间存在着显著的差别,主要是它们所支持的加密算法不同,所以TLS与SSL3.0不能互操作。
4.2 加密算法
** 1、 对称加密**
- 对称加密又叫做私钥加密,即信息的发送方和接收方使用同一个密钥去加密和解密数据。对称加密的特点是算法公开、加密和解密速度快,适合于对大数据量进行加密,常见的对称加密算法有DES、3DES、TDEA、Blowfish、RC5和IDEA。
- 对称加密中用到的密钥叫做私钥,私钥表示个人私有的密钥,即该密钥不能被泄露。所以该密钥不能直接在网络上传输。
** 2、 非对称加密**
- 对称加密的通信双方使用相同的密钥,如果一方的密钥遭泄露,那么整个通信就会被破解。而非对称加密使用一对密钥,即公钥和私钥,且二者成对出现。私钥被自己保存,不能对外泄露。公钥指的是公共的密钥,任何人都可以获得该密钥。用公钥或私钥中的任何一个进行加密,用另一个进行
- 由于加密和解密使用了两个不同的密钥,这就是非对称加密“非对称”的原因。非对称加密的缺点是加密和解密花费时间长、速度慢,只适合对少量数据进行加密。
4.3 数字证书
不对称加密也会有同样的问题,如何将不对称加密的公钥给对方呢?一种是放在一个公网的地址上,让对方下载;另一种就是在建立连接的时候,传给对方。
怎么鉴别别人给你的公钥是对的。会不会有人冒充网站,发给你一个它的公钥。接下来,你和它所有的互通,看起来都是没有任何问题的。毕竟每个人都可以创建自己的公钥和私钥。这时候就需要权威的机构来保证公钥的真实性了,也就是权威机构颁发证书。这个权威机构称为CA( Certificate Authority)。
数字签名算法
我们现实生活中比如派出所给你开一个证明的时候,也会给你盖上一个章或者签名,从而保证证明的真实性。数字证书也一样,要保证证书的真实性,就要有权威机构的签名,称为数字签名。数字签名的算法就叫做签名算法。
数字签名是使用数字证书与信息加密技术、用于鉴别电子数据信息的技术,可通俗理解为加盖在电子文件上的“数字指纹”。
数字证书是由权威公证的第三方认证机构(即CA,Certificate Authority)负责签发和管理的、个人或企业的网络数字身份证明。
要怎么签名才能保证是真的权威机构签名的呢?当然只有用只掌握在权威机构手里的东西签名了才行,这就是 CA 的私钥。
签名算法大概是这样工作的:一般是对信息做一个 Hash 计算,得到一个 Hash 值,这个过程是不可逆的,也就是说无法通过 Hash 值得出原来的信息内容。在把信息发送出去时,把这个 Hash 值加密后,作为一个签名和信息一起发出去。
要想验证证书,需要 CA 的公钥,问题是,你怎么确定 CA 的公钥就是对的呢?
所以,CA 的公钥也需要更牛的 CA 给它签名,然后形成 CA 的证书。要想知道某个 CA 的证书是否可靠,要看 CA 的上级证书的公钥,能不能解开这个 CA 的签名。就像你不相信区公安局,可以打电话问市公安局,让市公安局确认区公安局的合法性。这样层层上去,直到全球皆知的几个著名大 CA,称为 root CA,做最后的背书。通过这种层层授信背书的方式,从而保证了非对称加密模式的正常运转。除此之外,还有一种证书,称为 Self-Signed Certificate,就是自己给自己签名。这个给人一种“我就是我,你爱信不信”的感觉。
4.4 HTTPS 的工作模式
HTTPS单向认证(客户端认证服务端)流程(一共产生了三个随机数):
- c->s,客户端发起加密通信请求,这个请求通常叫做 ClientHello请求,告知自己支持的协议版本号,加密算法,压缩算法,以及一个用于生成后续通信密钥的随机数;
- s->c,服务端响应,也叫作 ServerHello,确认加密通信协议,加密算法,以及一个用于生成后续通信密钥的随机数,还有网站证书;
- c->s,客户端在收到上一步服务端的响应之后,首先会检查证书的颁发者是否可信任,是否过期,域名是否一致,并且从操作系统的证书链中找出该证书的上一级证书(寻找授信的CA的过程是不断往上追溯的),并拿出服务端证书的公钥,然后验证签名和hash,如果验证失败,就会显示警告,我们经常在Chrome里面看到,“此网站有风险,是否继续什么的”。如果验证通过,客户端会向服务端发送一个称作 “pre-master-key” 的随机数,该随机数使用证书的公钥加密,以及编码改变通知(以后就用协商的密钥堆成加密通信了),客户端完成握手。
- 服务端在收到上一步客户端请求之后,也会确认我以后发给你的信息是加密的,并且完成握手。
此时,客户端有第一步自己生成的随机数,第二步收到服务端的随机数,第三步的 pre-master-key,服务端也是如此,他们就可以用这三个随机数使用约定的算法生成同一个会话密钥(session key )来加密以后的通信数据了。
上面的过程只包含了 HTTPS 的单向认证,也即客户端验证服务端的证书,是大部分的场景,也可以在更加严格安全要求的情况下,启用双向认证,双方互相验证证书。
SSL协议在握手阶段使用的是非对称加密,在传输阶段使用的是对称加密,也就是说在SSL上传送的数据是使用对称密钥加密的。
因为非对称加密的速度缓慢,耗费资源。其实当客户端和主机使用非对称加密方式建立连接后,客户端和主机已经决定好了在传输过程使用的对称加密算法和关键的对称加密密钥,由于这个过程本身是安全可靠的,也即对称加密密钥是不可能被窃取盗用的,因此,保证了在传输过程中对数据进行对称加密也是安全可靠的,因为除了客户端和主机之外,不可能有第三方窃取并解密出对称加密密钥!如果有人窃听通信,他可以知道双方选择的加密方法,以及三个随机数中的两个。整个通话的安全,只取决于第三个随机数(pre-master secret)能不能被破解。
HTTPS的单向认证和双向认证
单向认证:
(1). 客户端保存着服务器端的证书并信任该证书即可
(2). HTTPS一般是单向认证,这样可以让绝大部分人都访问你的站点
双向认证:
(1). 先决条件是有两个或两个以上的证书,一个是服务器端证书,另一个或多个是客户端证书
(2). 服务器端保存着客户端的证书并信任该证书,客户端保存着服务器端的证书并信任该证书。这样,成功的情况下即可完成请求响应
(3). 双向认证一般企业应用对接
4.5 重放与篡改
有了加密和解密,黑客截获了包也打不开了,但是它可以发送 N 次。这个往往通过 Timestamp 和 Nonce 随机数联合起来,然后做一个不可逆的签名来保证。
Nonce 随机数保证唯一,或者 Timestamp 和 Nonce 合起来保证唯一,同样的,请求只接受一次,于是服务器多次受到相同的 Timestamp 和 Nonce,则视为无效即可。
如果有人想篡改 Timestamp 和 Nonce,还有签名保证不可篡改性,如果改了用签名算法解出来,就对不上了,可以丢弃了。
4.6 问题思考
HTTPS 协议比较复杂,沟通过程太繁复,这样会导致效率问题,有哪些优化方法?
- CDN接入
HTTPS增加的延时主要是传输延时RTT,RTT的特点是节点越近延时越少,CDN天然离用户最近,因此选择CDN作为HTTPS的接入口,能极大减少延时。 - 会话缓存
利用会话缓存从而复用连接,基于会话缓存建立的HTTPS连接不需要服务器使用私钥解密获取Pre-master信息,可以省掉CPU的消耗。 - 硬件加速
为接入服务器安装专用的SSL硬件加速卡。 - 远程解密
本地接入消耗过多的CPU资源,考虑将最消耗CPU资源的RSA解密计算任务转移到其他服务器。 - SPDY/HTTP2
这个是通过修改协议本身,利用TLS/SSL带来的优势,来提升HTTPS的性能。
参考文章
https协议 : https://www.jianshu.com/p/f9b8a3e62af1
网络&浏览器 : https://blog.csdn.net/qq_33262202/article/details/90318419