浅谈互联网通讯协议 | 青训营笔记

178 阅读24分钟

这是我参与「第四届青训营 」笔记创作活动的的第5天

对于一般的前端程序员来说,每天接触的多是 HTML、CSS、JS 等语言代码,对通讯协议的了解是较少的,恰巧在青训营系统地学习了相关的知识,便又课下查找了些资料,将内容总结分享出来。

HTTP 协议

HTTP 协议概述

HTTP 全称超文本传输协议(Hyper Text Transfer Protocol),是一种高级的获取文件的协议,主要分成两部分,即请求(Request)和响应(Response),该协议的默认端口号是 80。

客户浏览器在请求一个 Web 页面时,它首先与 Web 服务器建立连接;
连接成功后,它要将所请求的页面,所用的协议及版本,语言及版本,所能接收的 MIME 类型,编码类型以及连接状况等一些本地信息参数交送给服务器;
服务器收到请求后,发回所交送页面的信息的响应头信息(如协议认可,服务器类型,文档最后修改日期,长度等),然后才发送页面内容,最后双方断开连接。

由于一个 Web 页面中还可能包含有图像,声音,以及另外的超链接等,在客户机收到 Web 页面后,搜索其中的图像链接和声音链接,然后再请求这些页面。因此要完成一个完整的 Web 页显示,可能要建立多次的连接。从这个意义上来说,HTTP 是一个无连接、无状态的协议。

HTTP 工作过程

HTTP 的工作过程一般包括以下四步:

  • 客户端与服务器通过三次握手建立TCP连接

  • 服务器发出请求,利用请求头指出要检索的内容。请求头中第一行是请求行,包括请求方法、请求路径和协议版本。余下的行是某种类型的头部行,一般先是普通头部,然后是请求头部,最后是实体头部,回车换行标志请求头的结束。

    image.png

  • 服务器发出响应,包括响应头和响应体。服务器解析接收请求,生成包含了所请求资源的响应消息。使用响应字段传送有关服务器和进一步访问被请求资源的信息。这个过程主要由MIME解析器根据 HTTP 返回头完成其具体含义的处理,如包含压缩和字符集的说明、MIME 类型、返回数据的大小等信息。

    image.png

  • 客户端与服务器通过四次挥手TCP连接。如果客户端在请求头中包含了Connection: Keep-Alive字段,意为想要保持连接,而恰好服务器又支持的话,双方则不会执行四次挥手断开连接,服务器将继续等待客户的请求。只有服务器在等待至超时时间依旧没有收到客户端的请求时,服务器才自动关闭连接。

响应状态码

为简单明了的反馈本次响应的结果,从 HTTP/1.0 开始,各大互联网厂商都默契地在响应中使用 status 字段设置响应状态码,标记本次请求的处理结果。响应码在 HTTP/1.1 被正式写入协议中。响应码由三位数字组成,其中第一位区分了不同的状态码。

  • 1XX:这一类型的状态码,代表请求已被接受,但需要继续处理。这类响应是临时响应,只包含状态行和某些可选的响应头信息,并以空行结束。由于早期HTTP协议中没有定义任何 1xx 状态码,所以除非在某些试验条件下,一般服务器禁止向此类客户端发送1xx响应。
  • 2XX,这一类型的状态码,代表请求己被服务器正确的接收、理解、处理,且用户请求的资源已被发送。
  • 3XX,这一类型的状态码,代表被请求的资源己经被移到其他的服务器,需要进行重定向操作。这时需要从 Location 域中得到重定向的 URL 并再次发出请求。
  • 4XX,这一类型的状态码,代表客户端看起来可能发生了错误,妨碍了服务器的处理。协议要求服务器还应该返回一个解释当前错误状况的实体,以及这是临时的还是永久性的状况。
  • 5XX,这一类型的状态码,代表服务器在处理请求的过程中有错误或者异常状态发生,也有可能是服务器意识到以当前的软硬件资源无法完成对请求的处理。与4xx状态码一样,服务器也需要返回一个解释当前错误状况的实体,并说明这是临时的还是永久性的状况。

三次握手

客户端与服务器建立连接时需要双方共发送三次请求,以确保连接正确的建立,“三次握手”由此得名。建立连接前客户端处于 Closed 的状态,服务端处于 Listen 状态,三次握手的过程如下:

  • 第一次握手:客户端给服务端发一个 SYN 报文,并指明客户端的初始化序列号 ISN,此时客户端进入SYN_SEND 状态。

  • 第二次握手:服务器收到了客户端的SYN报文之后,会以自己的SYN报文作为应答,并且会在其中指定自己的初始化序列号ISN,同时会把客户端的ISN + 1作为ACK的值传回,表示自己已经收到了客户端的SYN,此时服务器进入SYN_REVD的状态。

  • 第三次握手:客户端收到了服务器传回的SYN 报文之后,会向服务器发送一个 ACK 报文,也是一样把服务器的ISN + 1作为ACK的值,表示已经收到了服务端的SYN报文,此时客户端会进入 ESTABLISHED 状态。服务器收到 ACK 报文之后,也处于 ESTABLISHED 状态,此时,双方已建立起了连接。

三次握手后,双方得知了对方报文的开始序号、发送数据的缓冲区大小、能被接收的最大报文段长度MSS以及被支持的TCP选项等。

image.png

四次挥手

客户端与服务器断开连接时需要双方共发送四次请求,以确保双方都得知连接断开,“四次挥手”由此得名。双方断开连接前都处于 ESTABLISHED 状态,四次挥手的过程如下:

  • 第一次挥手: 客户端会向服务端发送一个 FIN 报文,在报文中会指定一个序列号,表示自己数据发送完毕,要求断开连接。此时客户端进入FIN_WAIT1状态。

  • 第二次挥手:服务端收到客户端的FIN报文之后,会向客户端发送ACK报文,且把客户端的序列号值 +1作为ACK报文的序列号值,表明已经收到客户端的报文,此时服务端进入 CLOSE_WAIT 状态。

  • 第三次挥手:如果服务端也数据发送完毕想断开连接了,和第一次挥手一样,向客户端发送 FIN 报文,且指定一个序列号。此时服务端进入 LAST_ACK 状态。

  • 第四次挥手:客户端收到服务器的FIN之后,一样发送一个 ACK 报文作为应答,且把服务端的序列号值+1作为自己 ACK 报文的序列号值,此时客户端处于 TIME_WAIT 状态。需要过一阵子以确保服务端收到自己的 ACK 报文之后才会进入 CLOSED 状态,服务端收到 ACK 报文之后,就处于关闭连接了,处于 CLOSED 状态。

image.png

HTTP 发展史

HTTP/0.9

HTTP/0.9 是第一个版本的HTTP协议,它的组成极其简单,只允许客户端发送 GET 这一种请求,且不支持请求头。由于没有请求头,造成了 HTTP/0.9 协议只支持一种内容,即纯文本。不过网页仍然支持用HTML语言格式化,但无法插入图片。

HTTP/0.9具有典型的无状态性,每个事务独立进行处理,事务结束时就释放这个连接。由此可见,HTTP 协议的无状态特点在其第一个版本中已经成型。一次 HTTP/0.9 的传输首先要建立一个由客户端到服务器的 TCP 连接,由客户端发起一个请求,然后由服务器返回页面内容,然后连接会关闭。如果请求的页面不存在,也不会返回任何状态码。

HTTP 1.0

HTTP/1.0 是第一个在通讯中指定版本号的HTTP协议版本,也是第一个较为完善的HTTP协议版本,至今仍被使用。相对于 HTTP/0.9 增加了以下几个特性:

  • 请求与响应支持头部。

  • 响应对象以一个响应状态码开始。

  • 响应对象不再只限于文本。

  • 开始支持客户端向web服务器提交数据,支持GET、HEAD、POST方法。

  • 支持长连接(但默认还是使用短连接)、缓存机制以及身份认证。

HTTP 1.1

HTTP/1.1 是目前使用最广泛的协议版本。相对于HTTP/1.0新增了以下内容:

  • 默认为长连接,HTTP/1.1支持长连接和请求的流水线处理,在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟,在HTTP/1.1中默认开启Connection:keep-alive,一定程度上弥补了HTTP每次请求都要创建连接的缺点。

  • 提供了范围请求功能,在HTTP/1.0中,存在一些浪费带宽的现象,例如客户端只是需要某个对象的一部分,而服务器却将整个对象送过来了,并且不支持断点续传功能,HTTP/1.1则在请求头引入了range头域,它允许值请求资源的某个部分,即返回码是206,这样就方便了开发者自由的选择以便于充分利用带宽和连接。这是支持文件断点续传的基础。

  • 提供了虚拟主机的功能(HOST域),在 HTTP/1.0 中认为每台服务器都绑定一个唯一的IP地址,因此,请求消息中的URL并没有传递主机名。但随着虚拟主机技术的发展,每一台物理服务器上可以存在多个虚拟主机,并且它们共享一个IP地址。HTTP/1.1 请求消息和响应消息都应支持Host头域,且请求消息中如果没有 Host 头域会报告一个错误。

  • 缓存处理字段,HTTP/1.1在1.0的基础上加入了一些 cache 的新特性,引入了实体标签,一般被称为 e-tags,新增更为强大的 Cache-Control 头。

  • 错误通知的管理,在HTTP/1.1中新增了24个错误状态响应码,如409表示请求的资源与资源的当前状态发生冲突;410表示服务器上的某个资源被永久性的删除。

HTTP 2.0

HTTP/2.0在性能上做了很大优化,使HTTP协议的性能登上了一个新台阶,用于解决使用HTTPS协议后产生的性能问题,该版本也强制要求使用HTTPS。相对于之前的HTTP协议,新增了以下内容:

  • 二进制协议。在 HTTP/1.1 版中,报文的头信息必须是文本(ASCII 编码),数据体可以是文本,也可以是二进制。HTTP/2.0 则是一个彻底的二进制协议,头信息和数据体都是二进制,并且统称为"帧",可以分为头信息帧和数据帧。 帧的概念是它实现多路复用的基础。

  • 多路复用,HTTP/2.0 允许同时通过单一的连接发起多重的请求-响应消息。有了新的分帧机制后,HTTP/2.0 不再依赖多个TCP连接去处理更多并发的请求。每个数据流都拆分成很多互不依赖的帧,而这些帧可以交错(乱序发送),还可以分优先级。最后再在另一端根据每个帧首部的流标识符把它们重新组合起来。HTTP/2.0 连接都是持久化的,而且客户端与服务器之间也只需要一个连接(每个域名一个连接)即可。

  • 头信息压缩,由于 HTTP 1.1 协议不带状态,每次请求都必须附上所有信息。所以,请求的很多字段都是重复的,比如 Cookie 和 User Agent ,一模一样的内容,每次请求都必须附带,这会浪费很多带宽,也影响速度。HTTP/2.0 对这一点做了优化,引入了头信息压缩机制。一方面,头信息使用 gzip 或 compress 压缩后再发送;另一方面,客户端和服务器同时维护一张头信息表,所有字段都会存入这个表,生成一个索引号,以后就不发送同样字段了,只发送索引号,这样就能提高速度。

  • 请求优先级,浏览器可以在发现资源时立即分派请求,指定每个流的优先级,让服务器决定最优的响应次序。这样请求就不必排队了,既节省了时间,也最大限度地利用了每个连接。

  • 服务器推送,HTTP/2.0允许服务器未经请求,主动向客户端发送资源。服务端能把客户端所需要的资源伴随着index.html一起发送到客户端,省去了客户端重复请求的步骤。正因为没有发起请求,建立连接等操作,所以静态资源通过服务端推送的方式可以极大地提升速度。

HTTPS 协议

HTTPS 协议概述

HTTPS 全称安全超文本传输协议(Hyper Text Transfer Protocol over Secure Socket Layer),是以安全为目标的 HTTP 通道,在 HTTP 的基础上通过传输加密和身份认证保证了传输过程的安全性。

HTTPS 在 HTTP 协议下加入了SSL协议,SSL 协议是 HTTPS 的安全基础,详细内容的加密是 SSL 协议实现的。HTTPS 不同于 HTTP的 方面在于默认端口为 443,并且在 HTTP与 TCP 之间存在一个加密/身份验证层。它被广泛用于网络上安全敏感的通讯,例如交易支付等方面。

HTTPS 客户端和服务器能与某些加密信息格式标准相结合。HTTPS 支持多种兼容方案并且与 HTTP 相兼容。使用 HTTPS 的客户端能够与沒有使用 HTTPS 的服务器连接,反之亦然,但是这样的通讯不会利用HTTPS 安全特征。HTTPS 不需要客户端公用密钥认证,但它支持对称密钥的操作模式。这点很重要因为这意味着即使没有要求用户拥有公用密钥,私人交易也会发生。虽然 HTTPS 可以利用大多现有的认证系统,但 HTTPS 的应用并不必依赖这些系统。

HTTPS 提供了完整且灵活的加密算法、模态及相关参数。选项谈判用来决定客户机和服务器在事务模式、加密算法及证书选择方面取得一致意见。

在语法上,HTTPS 报文与 HTTP 相同,由请求或状态行组成,后面是信头和主体。但为了和 HTTP 报文区分开来,HTTPS 需要特殊处理,请求行使用特殊的安全途径和指定协议。因此 HTTPS 和 HTTP 可以在相同的 TCP 端口混合处理。HTTPS 报文由从客户机到服务器的请求和从服务器到客户机的响应组成。

HTTPS 响应行中的状态并不表明展开的HTTP请求的成功或失败。如果 HTTPS 处理成功,服务器会一直显示 200 OK,这就阻止了所有请求的成功或失败分析。客户端需要从加密数据中获取正确的状态码后再作判断

HTTPS 工作过程

由于 HTTPS 存在一个加密/身份验证层。在 HTTP 通信流程的基础上又增加了 SSL 加 密认证的环节,一般为以下五步:

  • 客户端使用 https 路径访问服务器,客户端与服务器通过三次握手建立TCP连接。

  • 客户端与服务器通过 SSL 四次握手确定会话密钥。

  • 客户端向服务器发出请求,请求信息使用会话密钥加密。

  • 服务器发出响应,响应信息同样用会话密钥加密。

  • 客户端与服务器通过四次挥手断开TCP连接。

SSL/TLS 协议

安全套接字协议(Secure Sockets Layer,SSL),及传输层安全(Transport Layer Security,TLS)是为网络通信提供安全及数据完整性的一种安全协议。TLS 与 SSL 在传输层与应用层之间对网络连接进行加密。因为两者功能与结构相同,经常会以 SSL 统称。

为了解决互联网上数据安全传输的问题,网景(Netscape)公司于 1994 年提出了 SSL 协议。从那时开始,SSL 历经多修改,现己发展到 SSL 3.0 版本。SSL 1.0 由 Netscape 公司开发后,只在内部使用,由于包含一些严重的错误,现在己不再发行。SSL 2.0 开发后就被加入到Netscape的Navigator l.0 中,但其中还包含了一些如中间攻击的弱点。最新的 SSL 3.0 规范在 1996 年 3 月正式发行,克服了SSL 2.0 中的缺陷,同时还加入了一些新的特征。Netscape Navigator 3.0和Microsoft 的 Internet Explorer 3.0 均可执行它。

SSL 3 发布以后, 得到了业界的高度重视。 之后IETF成立Transport Layer Security(TLS) 工作组,基于SSL 3 设计了 TLS, 分别于 1999 年、2006年和2008 年发布了 TLS 1.0、TLS 1.1和 TLS 1.2 , 逐步修补了协议在设计和实现中的漏洞, 并在2016 年出台具有更好完整性的 TLS 1.3。

目前, SSL协议已经作为一种工业标准大量应用于电子商务等网站中,目前国内大中型网站均已实现全站HTTPS覆盖。

通信加密

SSL的功能实现主要依赖三类基本算法:散列函数hash、对称加密、非对称加密

  • 常见的散列函数有MD5、SHA1、SHA256。该函数的特点是单向不可逆,对输入数据非常敏感,输出的长度固定,任何数据的修改都会改变散列函数的结果,可以有效防止信息的篡改并验证数据的完整性。

  • 常见的对称加密算法有AES-CBC、DES、3DES、AES-GCM等。相同的秘钥可以用于信息的加密和解密。只有掌握秘钥才能获取信息,可以防止信息窃听。但对称加密通信方式是一对一的,当服务器和多个客户端通信时,就需要维持多个密钥记录。

  • 常见的非对称加密算法有RSA、ECC、DH等。秘钥成对出现,一般称为公钥(公开)和私钥(保密)。公钥加密的信息只有私钥可以解开,私钥加密的信息只能公钥解开,因此掌握公钥的不同客户端之间不能相互解密信息,只能和掌握私钥的服务器进行加密通信。服务器可以实现一对多的的通信,客户端也可以用公钥来验证掌握私钥的服务器的身份。但非对称加密算法计算较为复杂,加密解密的速度不如对称加密。

综合上述算法特点,SSL的工作方式就是客户端先使用非对称加密与服务器进行通信,实现身份的验证并协商对称加密使用的秘钥。用散列函数生成摘要保证初次通信的信息不被篡改,然后使用对称加密算法以及协商好的秘钥对信息要进行加密通信。不同节点之间采用的对称秘钥不同,从而保证信息只能通信双方获取,并解决了两个算法各自存在的问题。

SSL 握手过程

SSL握手前有一些工作背景,这里要提到数字认证机构(Certificate Authority,CA)和其相关机关颁发的公开密钥证书,数字证书认证机构处于客户端与服务器双方都可信赖的第三方机构的立场上,负责解决身份伪装和数据篡改的问题。

浏览器/操作系统会内置一些可信的CA证书,其中包含CA的公钥。而浏览器会将其公钥和网站信息发送给CA,CA使用私钥对这些信息加密后得到服务器证书,发送回服务器,服务器持久保存。

SSL握手一般有以下5步:

  • 客户端向服务器发起请求:客户端生成随机数 R1 发送给服务端,并告诉服务端自己支持哪些加密算法和哈希算法。

  • 服务器向客户端发送数字证书:服务端生成随机数R2,从客户端支持的加密算法中选择一种双方都支持的加密算法(作为会话密钥的生成算法)和哈希算法(用于验证摘要信息)。服务端生成把服务器证书、随机数R2、选择的加密算法与哈希算法,一同发给客户端。

  • 客户端验证数字证书:首先浏览器会从内置的证书列表中索引,找到服务器下发证书对应的机构,如果没有找到,此时就会提示用户该证书是不是由权威机构颁发,是不可信任的。如果查到了对应的机构,则取出该机构的公钥、会话密钥生成算法、随机数R2。然后用机构的公钥解密得到服务器证书的内容,包括证书签名、网站的网址、网站的公钥、证书有效期等等。浏览器会验证这些内容的合法性、有效性、与访问的网址是否一致,一番发现问题就会提示用户。当这些都通过认证时,浏览器就可以安全使用证书中的网站公钥,客户端生成一个随机数 R3,用服务端证书中的公钥加密随机数R3并发送给服务端,然后根据会话密钥算法使用R1、R2、R3生成会话密钥

  • 服务器得到会话密钥:服务器用自己的私钥解密客户端发的随机数R3,根据会话密钥算法使用R1、R2、R3生成会话密钥。

  • 客户端与服务器进行加密会话:服务器和客户端依次把前面的所有内容通过哈希函数获取 hash 值,再使用会话密钥加密后发送给对方。接收方用会话密钥解密得到 hash 值进行信息完整性检验。双方都检验无误后,SSL 握手过程结束,以后的对话过程都使用会话秘钥加密信息后再传递。

HTTPS缺陷

HTTPS虽然可以认证用户与服务器,确保数据发送到正确的客户机与服务器,但仍有一些缺陷:

  • 客户端方面:相同网络环境下,HTTPS 协议会使页面的加载时间延长近 50%

  • 服务器方面:频繁的加密解密会消耗硬件资源,也会大量消耗 CPU 和内存,导致整个处理速度变慢,和传统 HTTP 相比,网络负载可能会增加2到100倍。

  • 开销方面:除去硬件的损耗,从数字认证机构购买证书也是需要开销的。

  • 安全方面:HTTPS 协议的安全是有范围的,在黑客攻击、拒绝服务攻击和服务器劫持等方面几乎起不到什么作用。而且SSL 证书的信用链体系并不安全。特别是在某些国家可以控制 CA 根证书的情况下,中间人攻击一样可行。

因为上面的原因,有些小网站还是选择使用HTTP协议,或者只部分采用HTTPS。

当然,随着技术的发展,上面的一些问题已得到改善,云计算技术降低了服务器的成本,TLS协议改善了算法,HTTP/2.0也提供了更多的性能优化。

未来版本——HTTP/3.0

HTTP/3.0 又称为 HTTP Over QUIC,由谷歌公司推出,与之前通讯协议相比做出了巨大的改变,最大的不同就是该版本弃用了TCP与SSL协议,改用UDP协议实现通信,并通过QUIC协议进行安全性、可靠性的验证。

HTTP/2.0 虽然已经通过许多重要优化使HTTP性能上了一个新台阶,但仍存在一些不足:建立连接时间长、队头阻塞、弱网环境表现不佳等等。这些不足基本都是由 TCP 协议引起的。但TCP协议栈是Linux内部的重要部分,基于 TCP 开发的设备和协议非常多,升级与修改TCP协议会导致难以处理的兼容问题。所以谷歌公司另辟蹊径,选择使用 QUIC 协议强化 UDP 协议,解决由TCP协议带来的问题。

快速 UDP 互联网连接(Quick UDP Internet Connection,QUIC)是谷歌制定的一种基UDP的低时延的互联网传输层协议。我们知道,TCP/IP 协议族是互联网的基础。其中传输层协议包括 TCP 和 UDP 协议。与 TCP 协议相比,UDP 更为轻量,但是错误校验也要少得多。这意味着 UDP 往往效率更高(不经常跟服务器端通信查看数据包是否送达或者按序),但是可靠性比不上 TCP。通常游戏、流媒体以及VoIP等应用均采用 UDP,而网页、邮件、远程登录等大部分的应用均采用 TCP。 

目前 QUIC 很好地解决了当今传输层和应用层面临的各种需求,包括处理更多的连接,安全性,和低延迟。QUIC 融合了包括 TCP,TLS,HTTP/2 等协议的特性,但基于 UDP 传输。QUIC 的一个主要目标就是减少连接延迟,当客户端第一次连接服务器时,QUIC 只需要 1RTT(Round-Trip Time)的延迟就可以建立可靠安全的连接,相对于 TCP+TLS 的 1-3 次 RTT 要更加快捷。之后客户端可以在本地缓存加密的认证信息,再次与服务器建立连接时可以实现 0-RTT 的连接建立延迟。QUIC 同时复用了 HTTP/2 协议的多路复用功能,但由于 QUIC 基于 UDP 所以就避免了HTTP/2的队头阻塞问题。因为 QUIC 基于 UDP,运行在用户域而不是系统内核,使得 QUIC 协议可以快速的更新和部署,从而很好地解决了 TCP 协议部署及更新的困难。

如今,IETF 的 QUIC 工作组正在负责 QUIC 协议的标准化进程。IETF 社群对于 QUIC 的标准化工作展现出了很高的兴趣。一个初步的 QUIC 协议版本已经被使用在谷歌的服务以及 Chrome 浏览器当中,并且被少数第三方开发者部署。需要注意的是 QUIC 的标准化工作完全开放,IETF 社群中的每个人都可以提出自己的建议,最终确定一个最佳方案。所以最后的标准化协议跟使用的版本可能会存在较大的不同。

结语

如果喜欢或有所帮助的话,希望能点赞关注,鼓励一下作者。

如果文章有不正确或存疑的地方,欢迎评论指出。