HTTP十六连问

649 阅读14分钟

本文正在参加「金石计划」

前言

作为计算机专业的学生,四大专业基础课是必须要牢牢掌握的,而其中又以计算机网络和操作系统最为重要。笔者虽然自认为对相关理论知识还算熟悉,奈何好不容易有个面试机会,一紧张又早把烂熟于心的知识点抛到九霄云外去了,再或者就是脑子一抽或者一时嘴瓢,面试官问我a我给叭叭了一通b,还半天都没反应过来说错了。

于是我深深地体会到,面试和考试一样也是需要提前准备的,绝不能张口就来。考试需要了解大致考察的范围,面试也一样。至少得知道相关领域大概会被问到什么类型的问题,而这些问题又大致可以从哪些方面去思考才行。

面试只有短短十五分钟到一个小时,不能完全等着面试官去挖掘自己会什么,对方没有那么多时间,主动展现自己很重要。

因此我在整理HTTP相关的知识点的过程中梳理出了十六个常见的问题,并以问答的形式展现出来,希望下次再有面试机会的时候不要嘴瓢了!

谈谈你对HTTP的理解?

HTTP,英文全称hypertext transfer protocol,中文释义“超文本传输协议”。

可以通过把这个名词拆解来理解这个概念:

  • 协议:这是计算机网络中贯穿始终的概念。它指的是一种约定俗成的通信规范。
  • 超文本:超越了普通文本,也就是说内容中不仅有文本,还可以有图像、音视频链接等等。比如HTML,(Hyper Text Markup Language),里面就有<img> <a href>等标签,用于展示纯文本以外的信息。
  • 传输:A到B的双向通信

那你认同HTTP是服务器和浏览器之间的协议这个说法吗?

这个说法比较局限和片面。因为我们说传输的通信双方,指的是一个抽象的点的概念,类似于物理学意义上的质点,它没有明确指代实体。比如A和B也可以同时是服务器。当然特定场景下这么说可以的,但它不能概括所有场景。

聊聊状态码?

状态码也是一种约定俗成的标记,分几类,分别以1 2 3 4 5开头,每一类都大致指明同一个性质的原因,方便排查。

  • 1xx:信息。100:服务端同意接受客户端的请求(一般是中间过程出现的,我实际中没见过)
  • 2xx表示成功。200就是成功;204也是成功,只不过它的response header没有body;206表示分块下载,断点续传
  • 3xx表示重定向。比如301 move permanently,资源已经永久迁移了;302 found,它表示资源还在,但需要用一个新的URL打开;304表示的是HTTP缓存,它会重定向到缓存文件。
  • 4xx:客户端错误。400:很笼统地说明bad request;403:bad request
  • 5xx:服务端错误。500:很笼统地说明internal server error;502:bad gateway

能讲讲HTTP缓存技术吗?

(看情况,如果时间较短感觉不适合说非重点内容的话下述标记为引用的内容就省略吧)

缓存(cache)的概念在计算机领域是通用的,比如计算机体系结构中有存储的金字塔多级分层模型,cache在上,内存在下;数据库之上又加了个缓存,比如Redis;应用层也有DNS缓存的概念等等。

它实际上就是考虑到访问本体的时间长,开销大,所以要在本体之前加入一个缓冲(备份),能通过访问备份解决的问题就不用去访问本体了。

HTTP中的缓存也是基于这样的思想原理。

那么,什么数据需要备份呢?一般都是使用频率高的。因为缓存相对于本体要更贵,容量更小,肯定是将一些经常访问的数据存在上面,不然总是不命中,又要去访问本体,就没有意义了。

但是如何保证缓存中的数据和真正的数据(比如这里的服务器)的一致性呢?这就是缓存技术要解决的问题了。

HTTP设计者很早就考虑到了要给缓存留位置,协议中留有了相应的字段————cache-control和expires。

使用这两个字段的方法是一种 “强制缓存” 的方式,它的专业术语叫 “page invalidation”

具体的实现原理是这样的,浏览器读取请求中的这两个字段,判断缓存是否过期,没过期就继续用,过期了就向服务器请求新数据。

一般而言,cache-control的优先级要高于expires。

而刚刚提到的3xx重定向状态码则涉及到另外一种缓存技术,它是一种 “协商缓存”,通常被称为 "conditional get" 。它是服务器去通知浏览器的一种方式。

原理是这样的:会用到请求头的if-modified-since 和响应头的last-modified,如果last-modified的时间与当前时间相隔太久,说明缓存可能已经失效了,那就用最新的数据,否则就走缓存。

和if-modified-since类似而且也更常用的是用请求头的if-none-match和响应头的 etag,每次对比etag前后有无变化,没则走缓存,有则请求。

标记的方式更准确,还能防止时间篡改。

GET和POST的区别?

这可以从两大方面去讲,一个是形式上/格式上/表现上(表),一个是内容上/职责(里)上。

  • 形式上,
    • get是参数直接写在URL上并且拼接;
    • post是将携带数据写在报文的body字段中
  • 内容上:
    • get的设计初衷是为了从服务器获取资源
    • post可以对服务器指定资源作处理(典型的方式是通过表单提交)

POST一定比GET安全吗?

中华文化博大精深,对安全的定义不同可能会得出两个完全相反的结论。

  • 网上很多文章都说POST安全,这是从数据传输过程中的隐私性去考虑的,他们认为,get直接把参数拼接在url中,旁人可以直接看到,而POST是将数据写在报文body字段中,相对来说安全一点。但实际上,这种安全是相对的,因为报文是可以通过抓包工具截获的。如果没有加密传输的话,其实区别不是很大。
  • 但安全还可以理解为“服务器上的数据没有被修改的风险”,在这种情况下,理论上get就是安全的,因为前面说到它的设计初衷是获取信息,而没有修改信息;相反,post可用于表单提交,它可以去改服务器上的数据,因此它反而是不安全的。 但这种说法同样存在过于理论化的问题。比如,实际业务场景中,当没有用到post来修改数据,那这种情况下它也是安全的;同理,虽然不推荐用get做表单处理,但是硬是要用也是可以的,我确实见过有的网站直接把这些信息参数拼接在url,那这种情况下get也不安全了。 因此,要结合实际场景、具体情况具体分析。

说到表单提交,如何防止用户重复提交呢?

这个问题很具有实践意义,据我观察,前人已经积累了非常多宝贵经验。比如:

  • 前端:一般提交后,提交按钮会变灰,而且会重定向到一个新页面,比如显示“提交成功”之类的。这样就是“按钮禁用”和防止用户强制刷新和后退。
  • 后端:服务端生成token,并在当前用户的session中保存,提交表单时也交token。若token与当前服务器的不一致,说明重复了,服务器就不作处理。

需要注意的是token是用一个隐藏域存储的,这也是为了防止用户刷新然后重提交。 因为同一浏览器的多个窗口共用一个session(比如在第一个窗口登录了,切换到其他窗口发现状态也已经改变了,如果没有,说明状态刷新还不够及时),如果1中提交,通过2进入页面,又会重新获得token,若是1刷新页面就又可以重新提交了,所以要隐藏token,并在后台比较是否与session中的值一致。

  • 后端中类似的思路还有缓存id法(这是从业务逻辑的角度去说的,前端获取后端缓存的唯一id,我想和上述说的应该是同一个东西,只是表述的角度不同,可以用到concurrenthashmap等)

  • 在数据库层面也可以设一个唯一索引,比如同一个id只能提交一次,重复的不写入。但这种直接操作数据库的方式在性能上有很大局限,而且应用场景也很局限。

HTTP和HTPPS的区别?

区别在于S,指的是secure。如何保证这种secure呢?关键在于它加入了SSL/TLS协议。

还有其他的一些表现上的区别:

  • HTTP端口是80,HTTPS是443
  • HTTPS需要向CA(certificate authentification)申请数字证书

详细说说SSL/TLS协议?/细说HTTPS建立连接的过程?

(这两个问题的区别在于后者需要说明第一步是TCP三次握手)

SSL:英文全称secure socket layer;

TLS:英文全称:transport layer secure

其实这两者指的是一个东西,只是最初叫前面的名字,后面修订了一些细则,规范为后面的名字。

TLS的原理可以用三句话概括:

  • 客户端向服务端索要、并且验证公钥
  • 两端协商生成私钥
  • 两端使用密钥进行通信

具体来说,全过程为四次握手:

sequenceDiagram
client->>server: 1. client hello
server->>client: 2. server hello
client->>server: 3. client response
server->>client: 4. server response

以下1234分别为图中标号对应阶段的内容,以使用RSA算法为例:

  1. client发送的信息包括如下三类:
    • client的TLS版本
    • client random
    • 支持的密码算法列表
  2. server发送的信息包括如下四类:
    • 确认TLS版本
    • server random
    • 确认所使用的密码算法
    • server数字证书
  3. client回复的信息包括如下三类:
    • 通过CA公钥确认数字证书的真实性
    • 从数字证书中获取公钥
    • 加密发送
      • pre-master-random
      • 告知对方之后的信息将通过加密发送
      • FIN
  4. server回复的信息包括如下两类:
    • 告知对方之后的信息将通过加密发送
    • FIN

在TLS1.3中对这个过程做了优化,只需要3次握手。

你刚刚提到的方式一定安全吗?有没有什么漏洞?

有的,比如刚刚用的是RSA加密算法,但如果服务器的私钥泄露,过去所有的密文一样会被破解。

解决方案:使用ECDHE这种密钥交换算法。和RSA相比,第四次握手前已开始发送加密数据。

客户端如何校验数字证书的真伪呢?

要回答这个问题,首先要理解数字证书的组成部分。 数字证书由CA(certificate authentification)签发。

  • 一个包,这个包中由公钥、颁发者、用途、有效时间组成,之后这个包会通过hash计算得到一个hash值。可以理解为这个hash值是一个id,标识着这个包,但哈希的过程是单向的,也就是不能由hash值直接推导出包里的内容。
  • 将hash值加密,生成签名
  • 签名+证书=数字证书

基于上述原理,客户端校验的是hash值。具体过程如下:

  • 客户端用相同的hash算法获取证书的hash1值
  • 浏览器/OS中一般已经集成了公钥信息,则用其可以得到hash2
  • 比较hash1和hash2是否相等

上述提到的方式绝对安全吗?

不会,其实这个校验机制涉及到证书信任链的问题。类比于DNS查找,不会每次都直接访问根服务器,而是会通过递归、迭代等方式层层向上访问,会有DNS缓存,如果上一级已经找到了就不再往再上一级了,这个数字证书校验也是同理。如果授权了上一级的证书为安全,就不再访问根证书,目的是希望尽可能地减少因为根证书出现问题而导致的下面所有鉴权受到影响。但是这种方式也会有问题,比如常见的“中间人攻击”,就是中间人伪造假证书,而用户选择了信任,则之后用户访问的都是虚假的信息。

但这种中间人机制也不是只有坏处,否则它也不能存在了。比如抓包工具的工作原理其实就是通过自己签发证书且被浏览器信任而取得中间人身份。

当然,要想解决这一问题,可以使用HTTPS双向认证。我对这个方面没有很深入去了解,但我观察到一个现象:尝试登录某些平台时,仅仅是在同一电脑上换了一个浏览器,也会要求重新校验身份,我想这应该是对应服务器对客户端的身份校验。

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

这个问题比较宽泛,我一时想不到它有什么特别针对性的措施,但我可以尝试从TLS协议的工作的全流程来讲讲。 TLS协议在实际工作时主要做了三件事情:

  • 压缩
  • 加密
  • 数据认证

image.png

HTTP1.1和2的区别是什么呢?

最大的区别是2采用的是二进制格式传输。 其他还有:

  • 2新增了头部压缩
  • 2支持并发传输
  • 2服务器能主动推送资源

那HTTP2有缺陷吗?

是有的,不然也不会有HTTP3了。

其实HTTP2最大的缺陷在于它依然没有在实质性地解决队头阻塞的问题,只是把它交给了TCP层,也就是计算机网络所说的上层依赖下层的服务。

但我们都知道,TCP是可靠传输的,一旦丢包,会触发重传机制。

你刚刚提到HTTP3,能详细说说吗?

HTTP3的最大特点就是把底层依赖从TCP换成了基于UDP的QUIC协议(quick udp internet control)

它有以下特点:

  • 无队头阻塞
  • 更快的连接建立(从名字就能看出来)
  • 连接迁移

这里结合具体应用场景去理解更容易一些。比如,在HTTP2中,TCP连接是通过四元组建立连接的(源ip,源端口,目标ip,目标端口),它有什么问题呢?我们都知道,ip其实是由网络接口唯一确定的,通常说的一台主机只有一个ip是因为一般情况下只给它接入一个网络接口,如果网络环境变化了,比如从wifi切换到流量,那么相应ip地址也会改变,这时候就需要重新建立连接。

但是基于UDP的QUIC不存在这个问题,它是通过连接id来标记两个通信端点,这样即使网络环境变化后也能不受影响,无缝复用原来的连接。

不过感觉现在最常用的依然是HTTP1.1 或者2,而3还不普及,因为很多设备并没有更新,它并不认识QUIC,就把它当做UDP包给丢弃掉了。

你的项目中用到了HTTP框架,那你说说你是怎么保证HTTP接口的安全性的?

我觉得这个问题可以被进一步细化为:如何保证接口的安全性。

  • 尽量使用HTTPS
  • token授权认证,未授权的用户无法获取数据
  • timestamp超时机制
  • URL签名,防止请求参数被篡改
  • 防止接口被第二次请求(防重放)

参考资料

  • 《computer network the fifth edition》Andrew S.Tanenbaum等
  • 小林coding——HTTP面试题(2023最新版)
  • 《图解HTTP》