网络协议十之http协议

 网络协议五层通天路,咱们从物理层、到链路层、网络层、再到传输层,现在又进一步,来到了应用层。这也是我们五层协议里最上面的一层,关于应用层,有太多协议要了解。但要说最有名的,那肯定就是 HTTP 了。

    HTTP 协议,几乎是每个人上网用的第一个协议,同时也是很容易被人忽略的协议。

    就像 http://blog.muzixizao.com/,是个 URL,叫作统一资源定位符。之所以叫统一,是因为它是有规定格式的。HTTP 称为协议,blog.muzixizao.com 是一个域名,表示互联网的一个位置。有的 URL 会有更详细的位置标识,例如

http://blog.muzixizao.com/?p=140

    正是因为格式是统一的,所以当你把这样一个字符串输入到浏览器的框里的时候,浏览器才知道如何进行统一处理。

HTTP 请求的准备

    浏览器会将 blog.muzixizao.com 这个域名发送给 DNS 服务器,让它解析为 IP 地址。关于 DNS 解析的过程,较为复杂,后面会专门介绍。

    域名解析成 IP 后,下一步是干嘛呢?

    还记得吗?HTTP 是基于 TCP 协议的,所以接下来就是建立 TCP 连接了。具体的连接过程可点击这里查看

    目前使用的 HTTP 协议大部分都是 1.1.在 1.1 协议里面,默认开启了 Keep-Alive 的,这样建立的 TCP 连接,就可以在多次请求中复用。虽然 HTTP 用了各种方式来解决它存在的问题,但基于TCP 的它,每次建立连接的三次握手以及断开连接的四次挥手,这个过程还是挺费时的。如果好不容易建立了连接,然后做一点儿事情就结束了,未免太浪费了。

HTTP 请求的构建

    建立了连接以后,浏览器就要发送 HTTP 的请求。请求的格式如下图:

    如图,HTTP 的报文大概分为请求行、首部、正文实体三部分。接下来,咱们就来一一认识。

请求行

    在请求行中,URL 就是 http://blog.muzixizao.com,版本为 HTTP 1.1。这里要说一下的,就是对应的请求方法。有以下几种类型:

1)GET 请求

    对于访问网页来讲,最常用的类型就是 GET。顾名思义,GET 就是去服务器获取一些资源。对于访问网页来讲,要获取的资源往往是一个页面。其实也有很多其他的格式,比如返回一个 JSON 字符串。当然,具体要返回什么,是由服务端决定的。

    例如,在云计算中,如果我们的服务端要提供一个基于 HTTP 协议的 API,获取所有云主机的列表,就会使用 GET 方法请求,返回的可能是一个 JSON 字符串,字符串里面是一个列表,列表里面会有各个云主机的信息。

2)POST 请求
    另一种类型叫做 POST。它需要主动告诉服务端一些信息,而非获取。而要告诉服务端的信息,一般都放在正文里面。正文里有各种各样的格式,最常见的的就是 JSON了。

    例如,我们平时的支付场景,客户端就需要把 “我是谁?我要支付多少?我要买什么?” 这样信息告诉服务器,这就需要 POST 方法。

    再如,在云计算里,如果我们的服务器,要提供一个基于 HTTP 协议的创建云主机的 API,也会用到 POST 方法。这个时候往往需要将 “我要创建多大的云主机?多少 CPU 和多少内存?多大硬盘?” 这些信息放在 JSON 字符串里面,通过 POST 的方法告诉服务器。

    除了上面常见的两种类型,还有一种 PUT 类型,这种类型就是向指定资源位置上传最新内容。但是 HTTP 的服务区往往是不允许上传文件的,所以 PUT 和 POST 就都变成了要传给服务器东西的方法。

    在我们的实际使用过程中,PUT 和 POST 还是有区别的。POST 往往是用来创建一个资源,而 PUT 往往是用来更新一个资源。

    例如,云主机已经创建好了,想对云主机打一个标签,说明这个云主机是生产环境的,另外一个云主机是测试环境的。我们修改标签的请求往往就是用 PUT 方法。

    还有 DELETE 方法。这个是用来删除资源的。

首部字段

    请求行下面就是首部字段。首部是 key-value 格式,通过冒号分割。这里面,往往保存了一些非常重要的字段。

  • Accpet-Charset:客户端可以接受的字符集。防止传过来的字符串客户端不支持,从而出现乱码;
  • Content-Type:正文格式。我们进行 POST 请求时,如果正文是 JSON,我们就应该将这个值设置为 application/json;
  • 缓存字段 Cache-Control、If-Modified-Since。

    这里重点认识下缓存字段。为什么要使用缓存呢?这是因为一个非常大的页面有很多东西。

    例如,我们浏览一个商品的详情,里面有商品的价格、库存、展示图片、使用手册等待。

    商品的展示图片会保持较长时间不变,而库存胡一根筋用户购买情况经常改变。如果图片非常大,而库存数非常小,如果我们每次要更新数据的时候都要刷新整个页面,对于服务器的压力也会很大。

    对于这种高并发场景下的系统,在真正的业务逻辑之前,都需要有个接入层,将这些静态资源的请求拦在最外面。架构就像下图:

    其中 DNS、CDN 会在后面的章节详细说明。这里咱们就先来了解下 Nginx 这一层。它是如果处理 HTTP 协议呢?对于静态资源,有 Vanish 缓存层,当缓存过期的时候,才会访问真正的 Tomcat 应用集群。

    在 HTTP 头里面,Cache-Control 是用来控制缓存的。当客户端发送的请求中包含 max-age 指令时,如果判定缓存层中,资源的缓存时间数值比指定时间的数值校,那么客户端可以接受缓存的资源;当指定 max-age 值为 0,那么缓存层通常需要将请求转发给应用集群。

    另外,If-Modified-Since 也是关于缓存的字段,这个字段是说,如果服务器的资源在某个时间之后更新了,那么客户端就应该下载最新的资源;如果没有更新,服务端会返回“304 Not Modified” 的响应,那客户端就不用下载了,也会节省带宽。

    到此,我们拼凑起了 HTTP 请求的报文格式,接下来,浏览器会把它交给传输层。

HTTP 请求的发送

    HTTP 协议是基于 TCP 协议的,所以它是以面向连接的方式发送请求,通过 stream 二进制流的方式传给对方。当然,到了 TCP 层,它会把二进制流变成一个个的报文段发送给服务器。

    在发送给每个报文段的时候,都需要对方有一个回应 ACK,来保证报文可靠地到达了地方。如果没有回应,那么 TCP 这一层会重新传输,直到可以到达。同一个包有可能被传了好多次,但是 HTTP 这一层不需要知道这一点,因为是 TCP 这一层在埋头苦干。

而后续传输过程如下:

  1. TCP 层封装目标地址和源地址。TCP 层发送每一个报文的时候,都需要加上自己的地址和它想要去的地址,将这两个信息放到 IP 头里面,交给 IP 层进行传输。
  2. IP 层获取 MAC 头。IP 层需要查看目标地址和自己是否在同一个局域网。如果是,就发送 ARP 协议来请求这个目标地址对应的 MAC 地址,然后将源 MAC 和目标 MAC 放入 MAC 头,发送出去;如果不在同一个局域网,就需要发送到网关,这里也要通过 ARP 协议来获取网关的 MAC 地址,然后将源 MAC 和网关 MAC 放入 MAC 头,发送出去。
  3. 网关转发。网关收到包发现 MAC 符合,取出目标 IP 地址,根据路由协议找到下一跳的路由器,获取下一跳路由器的 MAC 地址,将包发给下一跳路由器。
  4. 数据包到达目标地址的局域网。通过 ARP 协议获取目标地址的 MAC 地址,将包发出去。
  5. 目标地址检查信息,返回 ACK。目标机器发现数据包中的 MAC 地址及 IP 地址都和本机匹配,就根据 IP 头中的协议类型,知道是 TCP 协议,解析 TCP 的头,获取序列号。判断序列号是否是本机需要的,如果是,就放入缓存中然后返回一个 ACK,如果不是就丢弃。
  6. 根据端口号将数据包发送到指定应用。TCP 头里面还有端口号,HTTP 的服务器正在监听这个端口号。于是,目标机器自然指定是 HTTP 服务器这个进程想要这个包,就把数据包发给 HTTP 服务器。
  7. HTTP 服务器处理请求。HTTP 服务器根据请求信息进行处理,并返回数据给客户端。

HTTP 返回的构建

    HTTP 的返回报文也是有一定格式的,如下图:

状态行包含状态码和短语。状态码反应 HTTP 请求的结果。200 是大吉大利;404 则是我们最不想见到的,也就是服务端无法响应这个请求。短语中会说明出错原因。

首部 key-value。这里常用的有以下字段:

  • Retry-After:客户端应该在多长时间后再次尝试连接;
  • Content-Type:返回数据格式

    构造好了返回的 HTTP 报文,接下来就是把这个报文发送出去。当然,还是交给 Socket 去发送,交给 TCP,让 TCP 返回的 HTML 分成一个个小的数据段,并且保证每一段都安全到达。这些小的数据段会加上 TCP 头,然后交给 IP 层,沿着来时的路反向走一遍。虽然不一定是完全相同的路径,但是逻辑过程是一样的,一直到达客户端。

    客户端取出数据后 ,会根据端口号交给指定的程序,这时候就是我们的浏览器出马的时候。

    浏览器拿到了 HTTP 报文,发现返回 200,一切正常,就从正文中将 HTML 拿出来,展示出一个炫酷吊炸天的网页。

    以上就是正常的 HTTP 请求与返回的完整过程。

HTTP 2.0

    上面提到了,现在用到 HTTP 大多是 1.1 版本,而 HTTP 2.0 在 1.1 的基础上进行了一些优化,以期解决一些问题。

    HTTP 1.1 在应用层以纯文本的形式进行通信。每次通信都要带完整的 HTTP 头,而且不考虑 pipeline 模式的话,每次的过程都要像上面描述的那样一去一回。显然,在效率上会存在问题。

    为了解决这些问题,HTTP 2.0 会对 HTTP 头进行一定的压缩,将原来每次都要携带的大量 key-value 对在两端建立一个索引表,对相同的头只发送索引表中的索引。

    另外,HTTP 2.0 协议将一个 TCP 连接切分成多个流,每个流都有自己的 ID,而且流可以是客户端发给服务端,也可以是服务端发给客户端,它其实只是个虚拟的通道,除此之外,它还有优先级。

    HTTP 2.0 将所有的传输信息分割成更小的消息和帧,并对它们采用二进制格式编码。常见的帧有 Header 帧,用于传输 Header 内容,并且会开启一个新的流。还有 Data 帧,用来传输正文实体,并且多个 Data 帧属于同个流。

    通过这两种机制,HTTP 2.0 的客户端可以将多个请求分到不同的流中, 然后将请求内容拆分成帧,进行二进制传输。这些帧可以打散乱序发送,然后根据帧首部的流标识符重新组装,并且可以根据优先级,决定先处理哪个流的数据。

    针对 HTTP 2.0,我们来看一个例子。

    假设我们有一个页面要发送三个独立的请求,一个获取 CSS、一个获取 JS、一个获取图片 jsg。如果使用 HTTP 1.1,这三个请求就是串行的,但是如果使用 HTTP 2.0,就可以在一个连接里,客户端和服务端同时反思多个请求和回应,而且不用按照顺序一对一对应。

    如上图。HTTP 2.0 其实是将三个请求变成三个流,将数据分成帧,乱序发送到一个 TCP 连接中。

    HTTP 2.0 成功解决了 HTTP 1.1 的队首阻塞问题。同时,也不需要通过 HTTP 1.x 的 pipeline 机制用多条 TCP 连接来实现并行请求与响应,减少了 TCP 连接数对服务器性能的影响,加快页面组件的传输速度。

    HTTP 2.0 虽然大大增加了并发性,但由于 TCP 协议的按序处理的特性,还是会出现阻塞的问题。

    还记得咱们之前说过的 QUIC 协议吗?这时候就是它登场的时候了。

    它用以下四个机制,解决了 TCP 存在的一些问题。

QUIC 协议

机制一:自定义连接机制

    我们知道,一条 TCP 连接是由四元组标识的。一旦一个元素发生变化,就需要端口重连。这在移动互联网的情况下,当我们切换网络或者信号不稳定时,都会导致重连,从而增加时延。

    TCP 没办法解决上述问题,但是 QUCI 基于 UDP 协议,就可以在自己的逻辑里面维护连接的机制,不再以四元组标识,而是以一个 64 位的随机数作为标识 ID,而且 UDP 是无连接的,只要 ID 不变,就不需要重新建立连接。

机制二:自定义重传机制
    TCP 为了保证可靠性,通过使用序号应答机制,来解决顺序问题和丢包问题。

    任何一个序号的包发出去,都要在一定时间内得到应答,否则就会超时重发。这个超时时间就是通过**采样往返时间 RTT **不断调整的。其实,这个超时时间的采样是不太准确的。

    如上图。发送一个包,序号为 100,超时后,再发送一个 100。然后收到了一个 ACK101。这个时候客户端知道服务器已经收到了 100,但是往返时间怎么计算呢?是 ACK 到达时间减去后一个 100 发送的时间,还是减去前一个 100 发送的时间呢?前者把时间算短了,后者把时间算长了

    QUIC 也有一个序列号,是完全递增的。任何一个包发送一次后,下一次序列号就要加一。像我们上面的例子,在 QUIC 协议中,100 的包没有返回,再次发送时,序号就是 101 了,如果返回是 ACK100,就是对第一个包的响应,如果返回 ACK101,就是对第二个包的响应,RTT 时间计算相对准确,过程如下图:

    上面的过程中,有的童鞋可能会问了,两个序号不一样的包,服务器怎么知道是同样的内容呢?没错,这确实是个问题。为了解决这个问题,QUIC 协议定义了一个 Offset 的概念。

    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 所能容纳的最大缓存,是真正的窗口大小,显然,这样更加准确。

    另外,还有整个连接的窗口,需要对于所有的 stream 的窗口做一个统计。

小结

  • HTTP 协议虽然很常用,也很复杂,我们只需要重点记住 GET、POST、PUT、DELETE 这几个方法,以及重要的首部字段;
  • HTTP 2.0 通过头压缩、分帧、二进制编码、多路复用等技术提升性能;
  • QUIC 协议通过基于 UDP 自定义的类似 TCP 的连接、重试、多路复用、流量控制技术,进一步提升性能。

 

 之前说了 HTTP 协议的各种问题,但是它还是陪伴着互联网、陪伴着我们走过了将近二十年的风风雨雨。现在有很多新的协议尝试去取代它,来解决性能、效率等问题,但它还还能靠着“多年的情分”活的滋润。然而,近些年,因为致命的安全问题,它不得不升级成 HTTPS 了。

    就拿我们叫外卖来说,我们点外卖的数据包被黑客截获,然后在服务器回复你之前给你回复一个假消息:“好啊,你该付款了,把银行卡号、密码拿来。”,这时如果你真的把卡号和密码发给他,那你的钱包就真的危险了。

    为了解决这些问题,我们给 HTTP 引入了加密,变成了 HTTPS。大家千万不要以为 HTTPS 是个新的协议,它实际上就是:

HTTPS = HTTP + SSL 层

    这里的 SSL 层的主要工作就是加密。加密方式一般分为两种:对称加密非对称加密

    这两种加密算法,对称加密要比非对称加密的效率要高很多,性能也好很多,所以交互的场景下多用对称加密。

对称加密

    在对称加密算法中,加密和解密的密钥是相同的。也就是说,加密和解密使用的是同一个密钥。因此,使用者一定要做好保密功能,不能让第三方知道。

    假设叫外卖的你和第三方约定了一个密钥 A,你发送请求的时候用 A 进行加密,外卖网站也用 A 进行解密,这样就算黑客截获了你们的请求,但是没有正确的密钥,还是破解不了。

    看起来很好的解决了黑客的问题。但是这里又引入了一个问题,你和外卖网站怎么来约定这个密钥呢?如果这个密钥在互联网上传输,就必须还得用 B 密钥来加密,否则被黑客获取到 A,你们的交互还是不安全,而且,你们又怎么约定 B 呢?所以,只能通过线下传输

    线下传输的话,看过《肖申克的救赎》的博友应该知道,安迪越狱前给瑞德约定了一个地点,让他去那里拿一个信封,里面写着他的住处。

    那我们和外卖网站也可以用这样的骚操作,偷偷约定时间地点,它给你一个纸条,上面写着你们两个的密钥,然后就用这个密钥在互联网定外卖。

    打住打住,上面这个操作想想都不可思议,如果最初的互联网是这样发展的话,那相信肯定活不久。

    相信你也发现了,只有对称加密,就会陷入密钥安全问题的死循环里,这时候,就需要非对称加密了。

非对称加密

    在非对称加密中 ,加密和解密过程中使用两个不相同的密钥。一个是公开的公钥,另一个是谁都不给的私钥。公钥加密的信息,只有私钥才能解密,而私钥加密的信息,也只有公钥才能解密

    放到外面上面的叫外卖过程中,非对称加密的私钥由外卖网站保存,不会再网上传输,这样就保证了私钥的私密性。与之对应的公钥是可以在互联网上随意传播的,只要外卖网站把这个公钥给你,你们就可以安全的互通了。

    还是来看我们点外卖的过程。我们用公钥加密,说“我要豆浆加油条”。黑客在中间截获了这个数据包,但是他没有私钥,没法解密数据,因此可以顺利到达外卖网站。而外卖网站用私钥把这个报文解出来,然后回复,“我知道了,你付款吧,给我卡号和密码”。

    整个过程好像很安全,再也不怕黑客了。但是,先别太乐观,你的银行卡是安全了,但是外卖网站可还是有危险的。黑客有外卖网站的公钥,可以模拟发送“我要定外卖”这个信息。

    为了解决这个问题,看来一对公钥私钥是不够的,客户端也需要有自己的公钥和私钥,并且客户端也要把自己的公钥给外卖网站。

    这样,客户端给外卖网站发送信息的时候,用外卖网站的公钥加密,而外卖网站给客户端发送消息的时候,使用客户端的公钥。这样就算有黑客企图模拟客户端获取一些信息,或者半路截获回复信息,但是由于它没有私钥,这些信息它还是打不开。

    说了那么多,相信你也发现了,非对称加密也会有同样的问题,如何将不对称加密的公钥给对方?这时有两种可行方式,一种是放在一个公网的地址上,让对方下载,另一种就是在建立连接的时候传给对方。

    这两种方法也有相同的问题。作为普通网民,你怎么鉴别别人给你的公钥是对方的,而不是被黑客冒充的?要知道,每个人都是可以创建自己的公钥和私钥的,创建过程如下:

# bash
// 创建私钥:
openssl genrsa -out httpsprivate.key 1024

// 根据私钥获取公钥
openssl rsa -in httpsprivate.key -pubout -out httpspublic.pem

HTTPS 证书

    可以看到,通过工具,我们可以很容易的创建公钥和私钥,那么黑客也是可以创建的,咱们怎么知道外卖网站传过来的公钥是不是真的就是外卖网站的呢?这时候,就需要第三方机构来当这个中间人了。

    这就像我们的户口本一样,每个人都可以打印出来,说是真的户口本,但是去使用的时候,人家就只认有公安局盖章的户口本。这个由权威部门颁发的称为**证书(Certificate)。

    HTTPS 证书里面应该有以下内容:

  • 公钥:这是最重要的;
  • 所有者:说明证书是属于谁的,就像户口本上的姓名和身份证号,来证明这个户口本是你的;
  • 证书发布机构:看看你的户口本上有没有某某公安局的字样?
  • 证书有效时间:这个和咱们身份证有效期是一个意思。

    说完了证书的内容,就到了下一步,怎么获取证书?这就像家里添了个小公举,去哪里上户口呢?恐怕大家都知道去公安局。与之对应的,HTTPS 也有专门负责派发证书的机构,这个机构我们称为 CA(Certificate Authrity)。而证书则可以通过下面这个命令生成:

openssl req -key httpsprivate.key -new -out httpscertificate.req

    将这个请求发给 CA,CA 会给这个证书“盖”一个章,我们称为签名算法。这个签名用到 CA 的私钥进行签发,来保证签名不被伪造。

    签名算法大概是这样工作的:一般是对信息做一个 Hash 计算,得到一个 Hash 值,这个过程是不可逆的,也就是说无法通过 Hash 值还原回原来的信息内容。再把信息发出时,把上面得到的 Hash 加密后,作为一个签名和信息一起发出去。CA 给整数签名的命令是:

openssl x509 -req -in httpscertificate.req -CA cacertificate-pem -CAkey caprivate.key

    这个命令会返回 Signature ok,而 httpscertificate.pem 就是签名过的整数。CA 用自己的私钥给外卖网站的公钥签名,这就相当于给外卖网站背书,形成了外卖网站的证书。我们可以通过下面这个命令查看证书内容:

openssl x509 -in httpscertificate.pem -noout -text

    证书会显示以下内容:

  • lssuer:证书颁发者;
  • Subject:证书颁发给谁;
  • Validity:证书期限;
  • Public-key:公钥内容;
  • Sinature Algorithm:签名算法

    通过这种方式,我们访问外卖网站时,得到的不再是一个公钥,而是一个整数。这个证书里有发布机构 CA,你只要通过这个 CA 的公钥去解密外卖网站证书的签名,解密成功,Hash 对的上,就说明外卖网站的公钥是真实可信的。

    上述整个过程中,都有一个前提,CA 是可信的。但是,我们又怎么确定 CA 的公钥就是对的呢?这就像有的人在偏远农村搞了个假公安局一样(应该没人这么干吧),我们怎么知道公安局是不是假的呢?然后我们就会想到,我去县公安局确认下当地公安局的信息不就好了。没错,CA 也是这么干的。

    CA 的公钥也需要更牛的 CA 给它签名,然后形成 CA 的公钥。要想知道某个 CA 的证书是否可靠,要看 CA 的上级证书的公钥能不能解开这个 CA 的签名。这样追根溯源,直到全球皆知的几大著名 CA,我们称为Root CA,做最后的背书。正是通过这种层层授信背书的形式,保证了非对称加密模式的争吵运转。

    除此之外,还有一种证书, 称为Self-Signed Certificate,就是自己给自己签名。这个就给人一种“我就是我,不一样的烟火,你爱信不信”的感觉,有兴趣的博友可以自行搜索了解。

HTTPS 的工作模式

    上面说了对称加密和非对称加密的原理,我们知道了非对称加密在性能上远不如对称加密,那在 HTTP 中,能否将两者结合起来呢?例如,公钥私钥主要用于传输对称加密的密钥,而真正的双方大数据量的通信都是通过对称加密进行

    是的,HTTPS 协议的思路就是这样的。如下图:

    图比较长,整个过程最后的目标是生成在后续通信过程中使用的对称密钥,以及约定使用的加密算法。整体过程如下:

  1. 客户端明文发送 TLS 版本信息、加密套件候选列表、压缩算法候选列表等信息,另外还会发送一个随机数,在协商对称密钥的时候使用(你好,我想定外卖,但你要保密我点了什么。这是我的加密套路列表,还有一个随机数 A,你留着);
  2. 服务器返回 Server Hello 消息,告诉客户端,服务器选择使用的协议版本、加密套件、压缩算法等,还有一个随机数 B,用于后续进行密钥协商(你好,保密没问题,就按套路 2 来吧,我也给你一个随机数 B,你留着);
  3. 服务器给客户端证书;
  4. 客户端从自己信任的 CA 仓库中,拿 CA 的证书里面的公钥去解密服务器传来的证书。解密成功,说明外卖网站是可信的。这个解密过程,客户端可能胡不断往上追溯 CA、CA 的 CA、CA 的 CA 的 CA,直到一个授信的 CA 为止;
  5. 证书验证可信后,客户端会计算产生随机数字 Pre-master,发送Client Key Exchange,用证书中的公钥加密,再发给服务器;

    到此时,无论是客户端还是服务端,都有了三个随机数,分别是:A、B、Pre-master。通过这三个随机数,客户端和服务端可以产生相同的对称密钥。

    约定好对称密钥和加密算法,就可以用对称加密的形式进行加密通信了,后续的通信除了多了一步密钥校验的过程,HTTP 协议里的那些过程都不会少。

    不过上面的过程中只包含了 HTTPS 的单向认证,也就是客户端验证服务端的证书,这也是最常见的场景。不过在更加严格要求通信安全的情况下,也可以启用双向认证,双方互相验证证书。

    通过上面的整个过程,我们可以看出,HTTPS 协议并不是一个新的协议,它只是 HTTP 协议与一些加密算法的组合,用来保证通信的安全。

    虽然上面介绍的非对称加密方式,在现在看来是完美不可解的,但未来谁知道呢?正所谓“道高一尺魔高一丈”,加密安全路上永无尽头。

小结

  • 加密分对称加密非对称加密。对称加密效率高,但存在密钥传输的问题;非对称加密可以解决密钥传输的问题,但效率较低。
  • 非对称加密需要通过证书权威机构来验证公钥的合法性。
  • HTTPS 是综合了对称加密和非对称加密算法的 HTTP 协议。既保证了传输安全,也保证了传输效率。
posted @ 2022-08-11 01:15  云散轻尘  阅读(239)  评论(0)    收藏  举报