Skip to content

3.1 HTTP 常见面试题

HTTP 基本概念

HTTP 是什么?

HyperText Transfer Protocol。

HTTP 是一个在计算机世界里专门在「两点」之间「传输」文字、图片、音频、视频等「超文本」数据的「约定和规范」。

HTTP 常见的状态码有哪些?

HTTP/1.1加入了更多的状态码

 五大类 HTTP 状态码

  • 1xx提示信息,处理中的一种中间状态。

    • 101 Switching Protocols」协议切换,服务器已经理解了客户端的请求,并将通过 Upgrade 消息头通知客户端采用不同的协议来完成这个请求。比如切换到一个实时且同步的协议(如 WebSocket)以传送利用此类特性的资源。
  • 2xx :服务器成功处理了客户端的请求。

    • 200 OK」最常见成功码。如果是非 HEAD 请求(一种只请求页面首部的请求方式,和GET类似),服务器返回的响应头都会有 body 数据。

    • 201 Created」请求被成功处理并且在服务端创建了一个新的资源。

    • 204 No Content」与 200 OK 基本相同,但响应头没有 body 数据。用于只关注处理结果是否成功的场景。

    • 206 Partial Content」是应用于 HTTP 分块下载或断点续传,表示响应返回的 body 数据并不是资源的全部,而是其中的一部分。

      • HTTP/1.1可以进行部分数据的请求,HTTP/1.0没有这个状态码
  • 3xx:资源发生了变动,需要客户端重定向(请求新的URL)。

    • 301 Moved Permanently」表示永久重定向,说明请求的资源已经不存在了,需改用新的 URL 再次访问。

    • 302 Found」表示临时重定向,说明请求的资源还在,但暂时需要用另一个 URL 来访问。

      • 301 和 302 都会在响应头里使用字段 Location,指明后续要跳转的 URL,浏览器会自动重定向新的 URL。
    • 304 Not Modified」资源未修改,重定向已存在的缓冲文件,用于缓存控制。

  • 4xx :服务器无法处理请求,也就是错误码的含义。

    • 400 Bad Request」笼统的错误。

    • 401 Unauthorized」未认证。

    • 403 Forbidden」:服务器禁止访问资源,并不是客户端的请求出错。

    • 404 Not Found」:表示请求的资源在服务器上不存在或未找到。

  • 5xx服务器处理时内部发生了错误,属于服务器端的错误码。

    • 500 Internal Server Error」笼统通用的错误码。

    • 501 Not Implemented」表示客户端请求的功能还不支持,类似“即将开业,敬请期待”的意思。

    • 502 Bad Gateway」通常是服务器作为网关或代理时返回的错误码,表示服务器自身工作正常,访问后端服务器发生了错误。

    • 503 Service Unavailable」表示服务器当前很忙,暂时无法响应客户端。

HTTP 常见字段有哪些?

  • Host 字段:指定服务器的域名。

    • 一个IP可以绑定了多个主机(如通过Nginx反向代理)如果通过IP直接进行访问,需要通过主机名确定真正请求的服务
  • Content-Length 字段

    • 服务器在返回数据时,会有 Content-Length 字段,表明本次回应的数据长度。后面的字节就属于下一个回应了。
    • 通过这个可以解决TCP粘包问题
  • Connection 字段

    • 指定长连接(HTTP1.0默认短连接,1.1默认长连接)
    • 设置为Keep-Alive就是长连接
    • 开启长连接一个HTTP连接可以被复用
  • Content-Type 字段:服务器回应时告诉客户端,本次数据是什么格式

    • 客户端可以请求时通过Accept声明自己接受什么数据格式, */* 表示接受任意格式
  • Content-Encoding 字段

    • 表示服务器返回的数据的压缩方法。
    • 最常见 gzip
    • 客户端通过Accept-Encoding指定自己接受的压缩方式

GET 与 POST

GET 和 POST 有什么区别?

规范为GET 的语义是从服务器获取指定的资源,post是更改资源。

  • GET 请求的参数位置一般是写在 URL 中,只允许 ASCII 字符(非ASCII需要编码转换)
  • POST 请求携带数据的位置一般是写在报文 body 中,格式不限,大小不限制。
  • 浏览器会对 URL 的长度有限制(HTTP 协议本身对 URL 长度并没有做任何规定)。

GET 和 POST 方法都是安全和幂等的吗?

在 HTTP 协议里

  • 「安全」:请求方法不会「破坏」服务器上的资源。
  • 「幂等」:多次执行相同的操作,结果都是「相同」的。

RFC 规范定义的语义来看:

  • GET 方法就是安全且幂等的,因为它是「只读」操作。所以,可以对 GET 请求的数据做缓存,这个缓存可以做到浏览器本身上(彻底避免浏览器发请求),也可以做到代理上(如 nginx),而且在浏览器中 GET 请求可以保存为书签
  • POST 会修改服务器上的资源,所以是不安全的,且多次提交数据就会创建多个资源,所以不是幂等的。所以,浏览器一般不会缓存 POST 请求,也不能把 POST 请求保存为书签

但是实际过程中,两者功能可以互换,如SpringBoot,get 和 post 都能在 url 和 body 中携带参数,但是不建议。

实际因为 HTTP 传输的内容都是明文的,虽然在浏览器地址栏看不到 POST 提交的 body 数据,但是只要抓个包就都能看到了。所以数据并不是广义的安全,需要HTTPS 协议加密。

HTTP 缓存技术

强制缓存

强缓存指的是只要浏览器判断缓存没有过期,则直接使用浏览器的本地缓存,决定是否使用缓存的主动性在于浏览器这边。

如下图中,返回的是 200 状态码,但在 size 项中标识的是 from disk cache,就是使用了强制缓存。

强缓存利用 HTTP 响应头部(Response Header)的Cache-Control字段实现,是一个相对时间

具体的实现流程如下:

  • 当浏览器第一次请求访问服务器资源时,服务器会在 Response 头部加上 Cache-Control,Cache-Control 中设置了过期时间大小;
  • 浏览器再次请求访问服务器中的该资源时,会先通过请求资源的时间与 Cache-Control 中设置的过期时间大小,来计算出该资源是否过期,如果没有,则使用该缓存,否则重新请求服务器;
  • 服务器再次收到请求后,会再次更新 Response 头部的 Cache-Control。

是协商缓存

请求的响应码是 304,告诉浏览器资源没有改变,可以使用本地缓存的资源。

协商缓存可以基于两种头部来实现。

第一种:请求头部中的 If-Modified-Since 字段与响应头部中的 Last-Modified 字段实现,服务器通过比较两者时间先后判定资源是否修改。

  • HTTP/1.0只有这一种缓存方式,HTTP/1.1增加了其他缓存方式

第二种:请求头部中的 If-None-Match 字段与响应头部中的 ETag 字段(更可靠,资源可能修改时间变了单内容不变):

  • 响应头部中 Etag:唯一标识响应资源;
  • 请求头部中的 If-None-Match:当资源过期时,浏览器发现响应头里有 Etag,则再次向服务器发起请求时,会将请求头 If-None-Match 值设置为 Etag 的值。服务器收到请求后进行比对,如果资源没有变化返回 304,如果资源变化了返回 200。

注意,协商缓存这两个字段都需要配合强制缓存中 Cache-Control 字段来使用,只有在未能命中强制缓存的时候,才能发起带有协商缓存字段的请求

当使用 ETag 字段实现的协商缓存的过程:

  • 当浏览器第一次请求访问服务器资源时,服务器会在返回这个资源的同时,在 Response 头部加上 ETag 唯一标识,这个唯一标识的值是根据当前请求的资源生成的;
  • 当浏览器再次请求访问服务器中的该资源时,首先会先检查强制缓存是否过期:
    • 如果没有过期,则直接使用本地缓存;
    • 如果缓存过期了,会在 Request 头部加上 If-None-Match 字段,该字段的值就是 ETag 唯一标识;
  • 服务器再次收到请求后,会根据请求中的 If-None-Match 值与当前请求的资源生成的唯一标识进行比较
    • 如果值相等,则返回 304 Not Modified,不会返回资源
    • 如果不相等,则返回 200 状态码和返回资源,并在 Response 头部加上新的 ETag 唯一标识;
  • 如果浏览器收到 304 的请求响应状态码,则会从本地缓存中加载资源,否则更新资源。
  • 类似于版本号

HTTP 特性

HTTP 最突出的优点是「简单、灵活和易于扩展、应用广泛和跨平台」。

HTTP/1.1 的缺点有哪些?

HTTP 协议里有优缺点一体的双刃剑,分别是「无状态、明文传输」,同时还有一大缺点「不安全」。

1. 无状态双刃剑

其实HTTPS也是无状态的

好处:不需要额外的资源来记录状态信息,这能减轻服务器的负担。

坏处:在完成有关联性的操作时会非常麻烦,比如每次都需要验证身份。

解法方案:Cookie 、Session、Token。

2. 明文传输双刃剑

好处:是可方便阅读的,可以直接肉眼查看,为我们调试工作带了极大的便利性。

坏处:容易泄漏信息。

3. 不安全

HTTP 比较严重的缺点就是不安全:

  • 通信使用明文(不加密),内容可能会被窃听。
  • 不验证通信方的身份,因此有可能遭遇伪装。
  • 无法证明报文的完整性,所以有可能已遭篡改。

HTTP/1.1 的性能如何?

1. 长连接

持久连接的特点是,只要任意一端没有明确提出断开连接,则保持 TCP 连接状态。

但如果某个 HTTP 长连接超过一定时间没有任何数据交互,服务端就会主动断开这个连接。

HTTP1.1默认长连接,1.0默认短连接。

2. 管道网络传输

在同一个 TCP 连接里面,客户端可以发起多个请求,只要第一个请求发出去了,不必等其回来,就可以发第二个请求出去,可以减少整体的响应时间。

但是服务器必须按照接收请求的顺序发送对这些管道化请求的响应

如果服务端在处理 A 请求时耗时比较长,那么后续的请求的处理都会被阻塞住,这称为「队头堵塞」。

TIP

注意!!!

实际上 HTTP/1.1 管道化技术不是默认开启,而且浏览器基本都没有支持。大家知道有这个功能,但是没有被使用就行了。

3. 队头阻塞

当顺序发送的请求序列中的一个请求因为某种原因被阻塞时,在后面排队的所有请求也一同被阻塞了,会招致客户端一直请求不到数据。(TCP的特点,保证完整,有序)

HTTP 与 HTTPS

  • HTTP 是明文传输,有安全风险。HTTPS 在 TCP 和 HTTP 网络层之间加入了 SSL/TLS 安全协议,加密传输。
  • HTTP 连接建立相对简单,TCP 三次握手之后便可进行 HTTP 的报文传输。而 HTTPS 在 TCP 三次握手之后,还需进行 SSL/TLS 的握手过程,才可进入加密报文传输。
  • HTTP 默认端口号是 80,HTTPS 默认端口号是 443。

HTTPS 解决了 HTTP 的哪些问题?

  • 混合加密:实现信息的机密性,解决了窃听风险。
  • 摘要算法:为数据生成独一无二的「指纹」实现完整性,校验机制解决了篡改风险。
  • 身份证书:将服务器公钥放入到数字证书中,解决了冒充的风险。

1. 混合加密

HTTPS 采用的是对称加密非对称加密结合的「混合加密」方式:

  • 在通信建立前采用非对称加密的方式交换「会话秘钥」,后续就不再使用非对称加密。
  • 在通信过程中全部使用对称加密的「会话秘钥」的方式加密明文数据。

采用「混合加密」的方式的原因:

  • 对称加密只使用一个密钥,运算速度快,密钥必须保密,无法做到安全的密钥交换
  • 非对称加密使用两个密钥:公钥和私钥,公钥可以任意分发而私钥保密,解决了密钥交换问题但速度慢。
    • 公私钥对的生成算法依赖于单向陷门函数。
    • 单向陷门函数:一个较弱的单向函数。已知单向陷门函数 f,陷门 h,给定任意一个输入 x,易计算出输出 y=f(x;h);而给定一个输出 y,假设存在 f(x;h)=y,很难根据 f 来计算出 x,但可以根据 f 和 h 来推导出 x。
    • 主要是单向加密解密

2. 摘要算法 + 数字签名

摘要算法(哈希函数):计算出内容的哈希值,这个哈希值是唯一的,且无法通过哈希值推导出内容

但是中间人能将内容和哈希值一同修改(传输假的数据)。用非对称加密算法来解决,共有两个密钥:

  • 一个是公钥,这个是可以公开给所有人的;
  • 一个是私钥,这个必须由本人管理,不可泄露。

这两个密钥可以双向加解密的,比如可以用公钥加密内容,然后用私钥解密,也可以用私钥加密内容,公钥解密内容。

流程的不同,意味着目的也不相同:

  • 公钥加密,私钥解密。这个目的是为了保证内容传输的安全,因为被公钥加密的内容,其他人是无法解密的,只有持有私钥的人,才能解密出实际的内容;
  • 私钥加密,公钥解密。这个目的是为了保证消息不会被冒充,因为私钥是不可泄露的,如果公钥能正常解密出私钥加密的内容,就能证明这个消息是来源于持有私钥身份的人发送的。

一般我们不会用非对称加密来加密实际的传输内容,因为非对称加密的计算比较耗费性能的(算法强度复杂)。

所以非对称加密的用途主要在于通过「私钥加密,公钥解密」的方式,来确认消息的身份,我们常说的数字签名算法,就是用的是这种方式,不过私钥加密内容不是内容本身,而是对内容的哈希值加密

私钥是由服务端保管,然后服务端会向客户端颁发对应的公钥。如果客户端收到的信息,能被公钥解密,就说明该消息是由服务器发送的。

3. 数字证书

前面我们知道:

  • 可以通过哈希算法来保证消息的完整性;
  • 可以通过数字签名来保证消息的来源可靠性(能确认消息是由持有私钥的一方发送的);

在计算机里,权威的机构就是 CA(数字证书认证机构),将服务器公钥放在数字证书(由数字证书认证机构颁发)中,只要证书是可信的,公钥就是可信的。

数字证书的工作流程,我也画了一张图,方便大家理解:

数子证书工作流程

通过数字证书的方式保证服务器公钥的身份,解决冒充的风险。

HTTPS 是如何建立连接的?其间交互了什么?

SSL/TLS 协议基本流程:

  • TLS四次握手(不同算法不一样)
  • 双方采用「会话秘钥」进行加密通信。

RSA算法的TLS 协议建立的详细流程:

1. ClientHello

由客户端向服务器发起加密通信请求,也就是 ClientHello 请求,发送

(1)客户端支持的 TLS 协议版本。

(2)客户端生产的随机数(Clinet Random),后面用于生成「会话秘钥」条件之一。

(3)客户端支持的密码套件列表,如 RSA 加密算法。

2. SeverHello

服务器收到客户端请求后,向客户端发出响应,也就是 ServerHello。服务器回应的内容有如下内容:

(1)确认 TLS 协议版本,如果浏览器不支持,则关闭加密通信。

(2)服务器生产的随机数(Server Random),也是后面用于生产「会话秘钥」条件之一。

(3)确认的密码套件列表,如 RSA 加密算法。

(4)服务器的数字证书。

3.客户端回应

客户端收到服务器的回应之后,首先通过浏览器或者操作系统中的 CA 公钥,确认服务器的数字证书的真实性。

如果证书没有问题,客户端会从数字证书中取出服务器的公钥,然后使用它加密报文,向服务器发送如下信息:

(1)一个随机数(pre-master key)。该随机数会被服务器公钥加密。

(2)加密通信算法改变通知,表示随后的信息都将用「会话秘钥」加密通信。

(3)客户端握手结束通知,表示客户端的握手阶段已经结束。这一项同时把之前所有内容的发生的数据做个摘要,用来供服务端校验。

上面第一项的随机数是整个握手阶段的第三个随机数,会发给服务端,所以这个随机数客户端和服务端都是一样的。

服务器和客户端有了这三个随机数(Client Random、Server Random、pre-master key),接着就用双方协商的加密算法,各自生成本次通信的「会话秘钥」

两者的会话密钥都是基于这三个随机数生成的,其中最后一个随机数是不被外界所能捕获的,前两个是能被捕获的

前两个随机数是由客户端和服务器独立生成的,作用主要是增强随机性,提高密钥的安全性。

4. 服务器的最后回应

服务器收到客户端的第三个随机数(pre-master key)之后,通过协商的加密算法,计算出本次通信的「会话秘钥」。

然后,向客户端发送最后的信息:

(1)加密通信算法改变通知,表示随后的信息都将用「会话秘钥」加密通信。

(2)服务器握手结束通知,表示服务器的握手阶段已经结束。这一项同时把之前所有内容的发生的数据做个摘要,用来供客户端校验。

至此,整个 TLS 的握手阶段全部结束。接下来,客户端与服务器进入加密通信,就完全是使用普通的 HTTP 协议,只不过用「会话秘钥」加密内容。

CA 签发证书的过程:

  • 首先 CA 会把持有者的公钥、用途、颁发者、有效时间等信息打成一个包,然后对这些信息进行 Hash 计算,得到一个 Hash 值;
  • 然后 CA 会使用自己的私钥将该 Hash 值加密,生成 Certificate Signature,也就是 CA 对证书做了签名;
  • 最后将 Certificate Signature 添加在文件证书上,形成数字证书;

客户端校验服务端的数字证书的过程:

  • 首先客户端会使用同样的 Hash 算法获取该证书的 Hash 值 H1;
  • 通常浏览器和操作系统中集成了 CA 的公钥信息,浏览器收到证书后可以使用 CA 的公钥解密 Certificate Signature 内容,得到一个 Hash 值 H2;
  • 最后比较 H1 和 H2,如果值相同,则为可信赖的证书,否则则认为证书不可信。

但事实上,证书的验证过程中还存在一个证书信任链的问题,因为我们向 CA 申请的证书一般不是根证书签发的,而是由中间证书签发的,比如百度的证书,从下图你可以看到,证书的层级有三级:

对于这种三级层级关系的证书的验证过程如下:

最开始客户端只信任根证书 GlobalSign Root CA 证书的,然后“GlobalSign Root CA”证书信任“GlobalSign Organization Validation CA - SHA256 - G2”证书,而“GlobalSign Organization Validation CA - SHA256 - G2”证书又信任 baidu.com 证书,于是客户端也信任 baidu.com 证书。

总括来说,由于用户信任 GlobalSign,所以由 GlobalSign 所担保的 baidu.com 可以被信任,另外由于用户信任操作系统或浏览器的软件商,所以由软件商预载了根证书的 GlobalSign 都可被信任。

操作系统里一般都会内置一些根证书,比如我的 MAC 电脑里内置的根证书有这么多:

这样的一层层地验证就构成了一条信任链路,整个证书信任链验证流程如下图所示:

最后一个问题,为什么需要证书链这么麻烦的流程?Root CA 为什么不直接颁发证书,而是要搞那么多中间层级呢?

这是为了确保根证书的绝对安全性,将根证书隔离地越严格越好,不然根证书如果失守了,那么整个信任链都会有问题。

上面使用的是RSA加密,缺点:因为客户端传递随机数(用于生成对称加密密钥的条件之一)给服务端时使用的是公钥加密的,服务端收到后,会用私钥解密得到随机数。所以一旦服务端的私钥泄漏了,过去被第三方截获的所有 TLS 通讯密文都会被破解。

HTTPS 的应用数据是如何保证完整性的?

TLS 在实现上分为握手协议记录协议两层:

  • TLS 握手协议就是我们前面说的 TLS 四次握手的过程,负责协商加密算法和生成对称密钥,后续用此密钥来保护应用程序数据(即 HTTP 数据);
  • TLS 记录协议负责保护应用程序数据并验证其完整性和来源,所以对 HTTP 数据加密是使用记录协议;

TLS 记录协议主要负责消息(HTTP 数据)的压缩,加密及数据的认证,过程如下图:

具体过程如下:

  • 首先,消息被分割成多个较短的片段,然后分别对每个片段进行压缩。

  • 接下来,经过压缩的片段会被加上消息认证码(MAC 值,这个是通过哈希算法生成的),这是为了保证完整性,并进行数据的认证。通过附加消息认证码的 MAC 值,可以识别出篡改。与此同时,为了防止重放攻击,在计算消息认证码时,还加上了片段的编码。

  • 再接下来,经过压缩的片段再加上消息认证码会一起通过对称密码进行加密。

  • 最后,上述经过加密的数据再加上由数据类型、版本号、压缩后的长度组成的报头就是最终的报文数据。

记录协议完成后,最终的报文数据将传递到传输控制协议 (TCP) 层进行传输。

如果你想详细了解记录协议是如何分片、压缩、计算 MAC 值、分组加密,可以看这篇:理解 SSL/TLS 系列 (四) 记录协议

SSL 和 TLS 没有太大的区别。

SSL 指安全套接字协议(Secure Sockets Layer),首次发布与 1996 年。SSL 的首次发布其实已经是他的 3.0 版本,SSL 1.0 从未面世,SSL 2.0 则具有较大的缺陷(DROWN 缺陷——Decrypting RSA with Obsolete and Weakened eNcryption)。很快,在 1999 年,SSL 3.0 进一步升级,新版本被命名为 TLS 1.0。因此,TLS 是基于 SSL 之上的,但由于习惯叫法,通常把 HTTPS 中的核心加密协议混称为 SSL/TLS。

HTTPS 一定安全可靠吗?

之前有读者在字节面试的时候,被问到:HTTPS 一定安全可靠吗?

这个问题的场景是这样的:客户端通过浏览器向服务端发起 HTTPS 请求时,被「假基站」转发到了一个「中间人服务器」,于是客户端是和「中间人服务器」完成了 TLS 握手,然后这个「中间人服务器」再与真正的服务端完成 TLS 握手。

具体过程如下:

  • 客户端向服务端发起 HTTPS 建立连接请求时,然后被「假基站」转发到了一个「中间人服务器」,接着中间人向服务端发起 HTTPS 建立连接请求,此时客户端与中间人进行 TLS 握手,中间人与服务端进行 TLS 握手;
  • 在客户端与中间人进行 TLS 握手过程中,中间人会发送自己的公钥证书给客户端,客户端验证证书的真伪,然后从证书拿到公钥,并生成一个随机数,用公钥加密随机数发送给中间人,中间人使用私钥解密,得到随机数,此时双方都有随机数,然后通过算法生成对称加密密钥(A),后续客户端与中间人通信就用这个对称加密密钥来加密数据了。
  • 在中间人与服务端进行 TLS 握手过程中,服务端会发送从 CA 机构签发的公钥证书给中间人,从证书拿到公钥,并生成一个随机数,用公钥加密随机数发送给服务端,服务端使用私钥解密,得到随机数,此时双方都有随机数,然后通过算法生成对称加密密钥(B),后续中间人与服务端通信就用这个对称加密密钥来加密数据了。
  • 后续的通信过程中,中间人用对称加密密钥(A)解密客户端的 HTTPS 请求的数据,然后用对称加密密钥(B)加密 HTTPS 请求后,转发给服务端,接着服务端发送 HTTPS 响应数据给中间人,中间人用对称加密密钥(B)解密 HTTPS 响应数据,然后再用对称加密密钥(A)加密后,转发给客户端。

从客户端的角度看,其实并不知道网络中存在中间人服务器这个角色。那么中间人就可以解开浏览器发起的 HTTPS 请求里的数据,也可以解开服务端响应给浏览器的 HTTPS 响应数据。相当于,中间人能够“偷看”浏览器与服务端之间的 HTTPS 请求和响应的数据。

但是要发生这种场景是有前提的,前提是用户点击接受了中间人服务器的证书。

中间人服务器与客户端在 TLS 握手过程中,实际上发送了自己伪造的证书给浏览器,而这个伪造的证书是能被浏览器(客户端)识别出是非法的,于是就会提醒用户该证书存在问题。

如果用户执意点击「继续浏览此网站」,相当于用户接受了中间人伪造的证书,那么后续整个 HTTPS 通信都能被中间人监听了。

所以,这其实并不能说 HTTPS 不够安全,毕竟浏览器都已经提示证书有问题了,如果用户坚决要访问,那不能怪 HTTPS,得怪自己手贱。

另外,如果你的电脑中毒了,被恶意导入了中间人的根证书,那么在验证中间人的证书的时候,由于你操作系统信任了中间人的根证书,那么等同于中间人的证书是合法的,这种情况下,浏览器是不会弹出证书存在问题的风险提醒的。

这其实也不关 HTTPS 的事情,是你电脑中毒了才导致 HTTPS 数据被中间人劫持的。

所以,HTTPS 协议本身到目前为止还是没有任何漏洞的,即使你成功进行中间人攻击,本质上是利用了客户端的漏洞(用户点击继续访问或者被恶意导入伪造的根证书),并不是 HTTPS 不够安全

为什么抓包工具能截取 HTTPS 数据?

很多抓包工具 之所以可以明文看到 HTTPS 数据,工作原理与中间人一致的。

对于 HTTPS 连接来说,中间人要满足以下两点,才能实现真正的明文代理:

  1. 中间人,作为客户端与真实服务端建立连接这一步不会有问题,因为服务端不会校验客户端的身份;
  2. 中间人,作为服务端与真实客户端建立连接,这里会有客户端信任服务端的问题,也就是服务端必须有对应域名的私钥;

中间人要拿到私钥只能通过如下方式:

  1. 去网站服务端拿到私钥;
  2. 去 CA 处拿域名签发私钥;
  3. 自己签发受浏览器信任的证书;

不用解释,抓包工具只能使用第三种方式取得中间人的身份。

因此使用抓包工具进行 HTTPS 抓包的时候,抓包工具会生成根证书,导入到客户端系统的 受信任的根证书列表 中,这里的根证书实际上起认证中心(CA)的作用。

随后抓包工具使用该根证书签发域名的证书,因为根证书受信任,域名的证书同样会被浏览器信任。也就是抓包工具给自己创建了一个认证中心 CA,客户端拿着中间人(抓包工具)签发的证书去中间人(抓包工具)自己的 CA 做认证,这个证书当然被认为是有效的。

如何避免被中间人抓取数据?

我们要保证自己电脑的安全,不要被病毒乘虚而入,而且也不要点击任何证书非法的网站,这样 HTTPS 数据就不会被中间人截取到了。

当然,我们还可以通过 HTTPS 双向认证来避免这种问题。

一般我们的 HTTPS 是单向认证,客户端只会验证了服务端的身份,但是服务端并不会验证客户端的身份。

如果用了双向认证方式,不仅客户端会验证服务端的身份,而且服务端也会验证客户端的身份。服务端一旦验证到请求自己的客户端为不可信任的,服务端就拒绝继续通信,客户端如果发现服务端为不可信任的,那么也中止通信。

HTTP/1.1、HTTP/2、HTTP/3 演变

HTTP/1 ~ HTTP/3

HTTP/1.1 相比 HTTP/1.0 提高了什么性能?

HTTP/1.1 相比 HTTP/1.0 性能上的改进:

  • 使用长连接的方式改善了 HTTP/1.0 短连接造成的性能开销。
  • 支持管道(pipeline)网络传输,只要第一个请求发出去了,不必等其回来,就可以发第二个请求出去,可以减少整体的响应时间。

HTTP/2 做了什么优化?

  • HTTP/2 协议是基于 HTTPS
  • 头部压缩
  • 二进制格式
  • 并发传输
  • 服务器主动推送资源

HTTP/3 做了哪些优化?

传输层采用基于UDP协议的QUIC协议。

QUIC 有以下 3 个特点。

  • 无队头阻塞
  • 更快的连接建立
  • 连接迁移

所以,QUIC 是一个在 UDP 之上的 TCP + TLS + HTTP/2 的多路复用的协议。


读者问答

读者问:“我看文中 TLS 和 SSL 没有做区分,这两个需要区分吗?”

这俩实际上是一个东西。

SSL 是洋文“Secure Sockets Layer”的缩写,中文叫做「安全套接层」。它是在上世纪 90 年代中期,由网景公司设计的。

到了 1999 年,SSL 因为应用广泛,已经成为互联网上的事实标准。IETF 就在那年把 SSL 标准化。标准化之后的名称改为 TLS(是“Transport Layer Security”的缩写),中文叫做「传输层安全协议」。

很多相关的文章都把这两者并列称呼(SSL/TLS),因为这两者可以视作同一个东西的不同阶段。

读者问:“为啥 SSL 的握手是 4 次?”

SSL/TLS 1.2 需要 4 握手,需要 2 个 RTT 的时延,我文中的图是把每个交互分开画了,实际上把他们合在一起发送,就是 4 次握手:

另外,SSL/TLS 1.3 优化了过程,只需要 1 个 RTT 往返时延,也就是只需要 3 次握手:

T

正在精进