计算机网络基础题库


场景篇

1. 介绍一下OSI七层协议,各层都是做什么的?各自都有什么协议?

OSI七层协议的全称是开放互联系统协议,这个系统一共有七层,从上到下依次是:

应用层:这一层主要通过定义各种各样的应用层协议的头部,来完成用户所需要的目标功能,比如说HTTP协议通过定义cache-control这样的头部字段来完成浏览器的缓存控制,还有例如FTP协议、SMTP协议,也都是通过定义协议的相关字段来实现相关的功能的

表示层:这一层主要通过双方协商的相关字段来确定双方数据传输的时候的编码格式,比如说有ASCII格式等,意思是说将上层交付下来的报文基于这个ASCII这个格式来编码和解码

会话层:会话层主要用来控制底层传输层协议中TCP协议、UDP协议相关的会话建立,主要通过定义一些协议,来控制不同机器上用户之间建立以及会话的管理,比如说有RPC协议,SSL协议,TLS协议等

传输层:传输层主要是将上层的数据包交付到下一层的网络的,同时在下层网络层发生了异常的时候,在上层的传输层协议要提供必要的控制来保证数据到达对等端,最为典型的就是TCP协议了

网络层:网络层中的核心是路由器,可以说路由器的功能就代表了网络层的功能,主要是要完成网络中分组的分组转发,路由选择,同时在协议的支持下,对错综复杂的、异构的网络进行规划和编址,典型的协议就有IP协议,还有BGP协议等

数据链路层:网络层解决了异构网络数据网络之间的机器如何通信的问题,那么数据链路层就解决了局域网内的机器是如何通信的问题了,它将上层交付下来的数据转换为MAC帧,然后基于MAC地址(机器的物理地址)进行寻址,将具体的比特流发生到具体的机器上,常见的协议就有CSMA/CD协议,这个协议的全称是带载波监听的多路访问技术,完成的是局域网内的数据传输

物理层:物理层解决了从计算机或者物理设备发出的数字信号如何转换为光电信号的问题。

2. IP协议和TCP协议属于哪一层?

IP协议属于网络层,TCP协议属于传输层

3. 输入一个URL发生了什么?

举一个例子,假设输入了www.baidu.com到浏览器中,这时候发生了什么?

第一步,浏览器会解析你输入的URL得到必要的信息,然后封装成HTTP请求,比如说访问百度的这个URL,具体来说就是封装一个GET的HTTP请求,封装对象分别是

  • 请求行:HTTP协议的版本,选用的请求方式(Get or Post)
  • 请求头:协议的头部字段,比如说有keep-aliveconnectioncache-control这些字段
  • 空行:用来分割请求的首部和请求体的一个空行
  • 请求体:存放具体的数据,像这个GET请求就不会有数据

一般来说,执行完这个HTTP请求的封装的时候,就会交付到操作系统的协议栈中,但是这时候还少点信息,因为这时候给的URL是一个域名,在IP层是无法直接通过域名来找到对方的主机的,因此在这样的情况下,还需要通过DNS协议来找到对方的主机IP地址

第二步,基于DNS协议完成域名=>IP地址的解析,这个解析一般来说需要经过以下的步骤:

  • 客户端(浏览器)会发送一个DNS查询请求,会向本地域名服务器查询:这个url的ip地址是什么?如果本地域名查询到了,那么就直接返回到客户端,如果查询不到,它就会给根域名服务器的地址给本地域名服务器,也就是给.这个域名服务器的地址给它
  • 本地域名服务器再拿着这个根域名服务器的地址,然后去问这个根域名服务器,这个url的ip地址是什么?
  • 由于根域名服务器并不直接存储域名的IP地址映射,它存储的是各个顶级域名服务器的地址,因此这时候就会给.com的地址给它
  • 本地域名服务器查询顶级域名服务器,如果顶级域名服务器也不知道,就会给它发权威域名服务器的地址,也就是负责www.baidu.com这个域名的地址,这时候权威域名服务器如果发现它的缓存中有数据,那么就可以直接返回了,如果发现缓存中没有数据,就会直接报错

第三步,解析出来了IP地址后,就会交给底层的网络协议栈,通过系统调用Socket库中的相关功能,完成网络的传输

第四步,交由TCP协议进行打包和连接的建立,简单来说就是将上层的HTTP请求数据包包装成TCP报文,然后和对等端三次握手之后,将数据包发送出去。

第五步,TCP包在将数据报交付出去的时候,会经过IP层,这一层的主要作用是根据IP地址来决定要如何转换,在操作系统中,有一个叫做路由表的东西,在linux系统中可以通过route -a这样的指令来查看,在执行转发的时候,会将IP地址和这张表中的路由条目进行与运算,如果得到匹配的结果之后,这个数据包从哪个接口出去,用哪张网卡的IP地址作为IP数据包的包头的字段,就都知道了

第六步,当数据包来到了目标网段之后,这时候就会将IP包包装为MAC帧,具体的过程是这样的,首先就是先读取本机的MAC帧,它是通过读取本机的ROM来获取的,然后要获取对方的MAC地址,它是通过ARP协议来实现的,过程是本机向外广播说:”谁的IP地址是xxx,收到请回复”,然后收到这个广播的机器就会比对自己的IP地址,如果匹配上了,那么就会发送一个回包,说的是:”我的IP地址xxx,我的MAC地址是xxx”,然后本机收到之后,就会将这个映射IP=>地址写入到ARP缓存中,下次还得发数据的时候就用缓存中的内容就可以了

第七步,封装好MAC帧,到达了网卡,网卡将数据发送出去的时候,一开始是数字信号,然后通过网络适配器中的调频器之类的适配,将其转换为光电信号在电路上传输,最终就到达了目标机器

目标机器在收到这个包之后,就执行拆包等操作,拆出来HTTP请求的原包,然后解析请求,后台服务器返回一个html页面的数据,原路返回,原机器收到后,也是一顿拆包,然后最终浏览器得到了响应体中的数据,将这个数据渲染到了页面上了

4. DNS是如何解析的?属于哪一层的协议?

DNS的解析分为两种,分别是递归查询迭代查询,其中迭代查询的方式大致如下:

  • 客户端(浏览器)会发送一个DNS查询请求,会向本地域名服务器查询:这个url的ip地址是什么?如果本地域名查询到了,那么就直接返回到客户端,如果查询不到,它就会给根域名服务器的地址给本地域名服务器,也就是给.这个域名服务器的地址给它
  • 本地域名服务器再拿着这个根域名服务器的地址,然后去问这个根域名服务器,这个url的ip地址是什么?
  • 由于根域名服务器并不直接存储域名的IP地址映射,它存储的是各个顶级域名服务器的地址,因此这时候就会给.com的地址给它
  • 本地域名服务器查询顶级域名服务器,如果顶级域名服务器也不知道,就会给它发权威域名服务器的地址,也就是负责www.baidu.com这个域名的地址,这时候权威域名服务器如果发现它的缓存中有数据,那么就可以直接返回了,如果发现缓存中没有数据,就会直接报错

迭代查询中的请求者都是本地域名服务器,也就是说这种模式中,根域名服务器这一类的服务器是只指路不带路

而递归查询则是带路,后续的查询工作需要根域名服务器这些服务器来完成

5. 输入一个域名,是怎么知道端口号的?

首先,通过域名是只能够知道IP地址的,是无法知道端口的,但是对于HTTP请求或者是HTTPS请求来说,有一个默认的端口号是80和443,它会先去尝试这个端口号能否完成通信,如果无法完成通信就报错

但是对于一些完成有特殊需求的,比如说像Java开发的Tomcat服务器,端口通常是8080,这个端口必须指明,否则无法访问

6. 如果浏览器没有显示页面有哪些原因?

这个问题从输入URL之后发生了什么为切入点进行思考

(1)输入的URL有问题,url的组成是<协议类型:ip:端口/域名/文件路径>,可能是文件路径输错了,在服务器上找不到这个文件,就空白了

(2)url中,ip/端口不对

(3)TCP连接出现问题,网络超时,导致页面没有及时传输过来

(4)IP层出现问题,比如说路由器挂掉了,无法完成分组转发

(5)数据链路层中,底层的ARP缓存中数据不正确,就是说ARP缓存的是旧数据,所对应的机器的MAC地址已经失效,需要重新发广播请求

7. 客户端TCP连接一个不存在的IP地址的服务端会发生什么?

这个问题就是在Linux中执行ping xxx.时候,如果输错了IP地址会发生什么?

这个问题我需要从两种情况进行回答:

首先第一种情况,当目的的IP地址和本机的IP地址处在同一个局域网的时候,由于机器在转发的时候,它有一个机制,就是拿到一个数据包,它会先去判断这个IP是否和主机本机地址处于一个局域网中,如果处于一个局域网中的话就不会走路由表,否则的话就会去走路由表的相关判断

因此在这样的情况下,它会直接将上层的TCP交付到IP层,然后IP层包装好目的IP地址和本地的IP地址的之后,就会将这个包交给数据链路层,数据链路层首先是基于ARP协议,在局域网内广播:谁的IP地址是xxx,这时候因为你的IP地址就是不存在的,所以在这样的情况下,那么就肯定收不到回复了,于是无法组成MAC帧在局域网内传播。

第二种情况,当目的的IP地址和本机的IP地址不是处在同一个局域网的时候,本机会查询路由表,一般来说会匹配到默认路由,就是本局域网的默认网关,然后就会将这个TCP报文发向这个默认网关,默认网关收到后,也会查路由表,不过因为这个IP地址不存在,因此会在网络中不断转发,直到TTL耗尽,此时客户端不会收到响应,因此会不断超时重传,超时重传达到一定的次数之后,就会直接断开连接了

第三种情况,就是这个IP地址所属的局域网网段在网络中是存在的,但是在网络中不存在,在这样的情况下,被发送到目的网段之后,就会回到第一种情况,无法组装成MAC帧,最终就无法响应了

8. 客户端 tcp 连接一个ip地址存在但是端口不存在的服务端会发生什么?

首先,IP地址是存在的,那么这就意味着你的SYN报文可以正常达到对方的机器,然后对方机器收到你这个包之后,通过网络协议栈的处理,发现在系统中并没有任何一个进程在监听这个端口,这时候TCP协议会认为这是个错误,于是内核就会发送一个RST的复位报文,重置连接

9. 客户端UDP发送一个IP地址存在但是端口不存在的报文会发送什么?

首先,IP地址是存在的,这就意味着UDP报文可以正常到达对方的机器,然后对方的机器收到这个包之后,发现本机上并没有任何一个进程在监听这个端口,于是这时候UDP包会被简单地丢弃。

但是要注意,此时ICMP协议会帮我们打小报告,也就是说当收到UDP包之后,会返回差错报文信息,这个差错报文信息的类型是端口不可达,这时候的含义是:你的UDP报文正确达到了对方的机器,但是端口是无效的

HTTP篇

1. HTTP的报文格式是怎么样的?是如何分割的?

HTTP的报文可以分成是HTTP请求报文HTTP响应报文,这两种报文的格式分别是:

HTTP请求报文:<请求行(包含有HTTP协议的版本,所用的请求方法)

请求头(包含有HTTP协议中规定的协议头部字段,比如说有cache-control,content-type)

空行(CR+LF),用来分割请求头和请求体>

请求体(Post请求一般会携带相关参数,Get请求一般将参数放在URL上)

HTTP响应报文:<响应行(包含有HTTP协议的版本,响应码,关于这个响应码的简要说明)

响应头(包含有HTTP协议中规定的协议头部字段,比如说有Content-Type,用来告诉客户端本次返回的数据格式)>

空行(CR+LF),用来分割请求头和请求体

响应体(返回本次服务端响应的内容)

2. HTTP有哪些方法?

HTTP请求的方法有:Get、Post、Put、DELETE、Head等

3. Get请求和Post请求有什么区别?Get请求一定具有幂等性吗?

关于他们的区别,可以从以下这几个方面进行讲述,首先从RFC的语义来看

Get请求是从服务端上获取资源,它是可以被缓存的,意味着对服务端的操作是只读的,它是安全而且幂等的

Post请求是向服务端上推送资源,本质上是根据这个Post的请求报文来对服务器上的资源进行修改,它会更新服务器上的资源,同时由于报文中携带数据,可能有一定的安全隐患,同时由于对服务端上的资源做了修改,因此它不是幂等的

从报文的格式来说:

Get请求一般不在请求体中携带参数,而是在URL上携带参数,这也就意味着有一定的限制,因为URL只支持ASCII码,同时长度具有一定的限制,不适合携带大量的二进制数据

Post请求一般是在请求体中携带参数,它支持传输二进制的数据,同时参数不会暴露在URL上。

问题:Get请求一定具有幂等性吗?

不是,从RFC的语义来讲,Get请求就是只读的,无法你触发多少次,最终的结果都是一样的,因为只读文件而不会修改文件,但是在实际开发中,这取决于开发者,如果开发者在返回资源的时候,对服务器上的资源做了修改,那么这时候就肯定不是幂等的了

关于安全的说法:安全是指传输的报文会不会被篡改,会不会被窃取,如果使用HTTP的话就肯定不是安全的,因为HTTP是明文传输的,要实现安全,可以使用引入了TLS/SSL协议的HTTPS协议

4. HTTP有什么状态码?

HTTP的状态码比较多,但是可以根据百位数来确定这些状态码的大致含义是什么

1xx:这种状态码比较少见,我见过的只有在网站协议从简单的HTTP协议升级成WebSocket协议的时候看到过,在服务器返回支持协议升级的时候,这时候就会返回一个101的状态码,告诉客户端,目前正在的进行通信协议需要更换了.

2xx:对方正常响应,也就是说报文被收到了而且正常处理,一般来说有:

  • 200 OK:表示服务器处理成功,一般来说会给一个content
  • 204 Not Conent:和200的含义是一致的,但是返回的响应体中没有数据
  • 206 Partial Content:常见于断点续传和分块下载,表示当前分片处理成功了,是全部数据的一部分处理成功了

3xx:表示资源路径的变更情况,主要来说有:

  • 301 Moved Permanently表示永久重定向了,这时候会返回一个Location字段,其中的值就是要重定向的地址,永久重定向的表现为:你浏览器的地址栏的url变成了这个location的地址
  • 302 Found表示临时重定向,表示资源还存在,但是暂时需要用其他的url进行访问
  • 304 Not Modified:这个状态码通常出现在HTTP协议中的缓存处理中,通过这个状态码就知道当前的缓存没有过期,可以接着使用

4xx:一般来说是前端的错误,主要来说有:

  • 400 Bad Request表示你的请求报文有问题,服务端无法解析,但是是一个非常笼统的错误反馈
  • 403 Forbidden前端发送的报文是没有问题的,但是服务端拒绝让你访问这个资源
  • 404 Not Found前端给的路径有问题,服务端上找不到这个资源

5xx:一般来说是服务端有问题,主要来说有:

  • 500 Intetnal Server Error:服务器的内部错误,表示服务器处理产生了异常
  • 501 Not Implemented:暂时没有实现,请以后再来
  • 502 Bad GateWay:代理服务器可以正常工作,但是实际工作的服务器产生了异常
  • 503 Service Unavilable:当前服务器很忙,暂时无法响应客户端

5. 重定向是哪一类状态码?临时重定向和永`久重定向有什么区别?

重定向是3xx的状态码,关于临时重定向的区别和永久重定向的区别有:

  • 临时重定向是302状态码,这时候你浏览器的URL并不会变成Location中的url
  • 永久重定向是301状态码,这时候浏览器的URL会变成Location中的url

6. HTTP1.1 和HTTP2.0的区别?

在具体HTTP1.1之前,可以先讲讲HTTP1.0的特性,然后过度到HTTP1.1

HTTP1.0的特性

HTTP1.0是短连接的连接维持方式,也就是说在底层的TCP完成三次握手之后,就发送一次数据之后就会发送四次挥手然后结束通信,因此开销是比较大的

第二个特性是它存在一个HTTP层面的请求队头阻塞的问题,这个问题是这样说的,HTTP1.0仅支持串行的发送HTTP请求,也就是说只有当上一个请求发送出去了,后面的请求才能继续发送,这个问题的本质原因是因为它仅支持短连接,根本无法在同一条TCP连接上同时发送HTTP报文

第三个特性是HTTP1.0是明文传输的,头部没有做压缩,传送数据是用的纯文本的格式,这意味着机器在收到这个报文之后,还需要将文本格式的数据转化为二进制格式的数据之后才能读取

HTTP1.1的改进与特性

HTTP1.1改进了短连接,实现了底层的TCP连接的连接复用,通过底层TCP连接的连接复用,可以减少因为三握四挥造成的额外开销。

第二个特性是它解决了HTTP1.0中请求队头阻塞的问题,通过一种叫做管道(可以同时发送多个HTTP请求而不必等到响应回来)技术来实现的,提高了HTTP报文的发送效率,但是这个特性带来的问题是响应队头阻塞的问题,这个问题具体来说就是,在接收响应的时候,只能够按照请求的顺序来接收响应并且处理,后面发送请求但是先到来的响应,尽管数据已经被接收了,但是依然无法提交到用户缓冲区中供其使用,造成一定的浪费

HTTP1.1还没有解决的问题和性能瓶颈

  • 请求的头部没有经过压缩,每次都需要发送大量冗余的头部,比如说Content-Type这样的字段,通常来说在HTTP请求中不会经常变化,但是每次请求都会带上这个请求头,造成一定的浪费
  • 报文明文传输,不安全
  • 报文是以文本格式定义的,这意味着如果它要被计算机处理,那么首先要经过二进制的转换,所以在这样的情况下,会增加一定的开销
  • 好好的全双工的TCP被HTTP协议完成了单工协议,这样的话无法完全利用底层的TCP协议

HTTP2.0的改进以及它与HTTP1.1的区别有哪些?

HTTP2.0解决了头部开销的相关问题,由于每次都会携带大量冗余相同的头部字段,那么它采用了一种叫做HPACK的算法,这个算法的工作流程是将HTTP头部中的这些字段存储到机器上的一本字典中,举个例子Content-Type = application/json,这个键值对会被记录到一本字段中,并且会获得一个索引号,比如说3,这样的话就将大量的字符压缩成了一个整形,HTTP解析头部的过程,只需要到字典中去查询这个索引号所对应的数据就可以了

第二个改进的地方,HTTP2.0变得安全了,它的底层是基于HTTPS这样的协议来保证数据不会明文传输,保证不会被篡改等

第三个改进的地方,HTTP2.0将报文的编码格式换成了二进制编码格式,虽然这样对人不友好,但是对计算机是友好的,计算机只需要读取这个报文,而不需要对报文做编码转换,提高了解析的效率

第三个改进的地方是就解决了HTTP层面的响应队头阻塞,HTTP2.0中提出了一种叫做Stream的技术,这种技术主要实现了并发传输,实现原理是:首先在一个TCP连接中,可以同时传输多个请求/响应,这些请求和响应被包装成Message,然后一个Stream会运输若干个这种Message,当这些Stream到达对等端之后,这时候就会根据Stream头部中的StreamId字段,拼装成完整的HTTP报文,这也就意味着,不同的HTTP请求可以同时发送,同时对等端也能够有能力并发处理这些响应,意思是说不必按照请求的发送顺序来处理响应了,而是谁的响应先到,谁先被组装成完整的HTTP报文的话就可以先处理了,这就很好的解决了队头响应阻塞的问题

第四个改进的地方就是实现了服务器资源推送的功能,客户端和服务端都可以新建Stream,通过客户端发送的StreamId都是奇数,服务器发送的StreamId都是偶数的方式来区分Stream,通过这样的区分,就可以实现双向数据的传输而不至于混淆双方的数据,充分利用了TCP协议全双工的特点。

HTTP2.0有什么缺点?

缺点主要有:

  • 存在一个TCP层面的队头阻塞,TCP层面的队头阻塞是讲,当TCP的滑动窗口不够大的时候,这时间会将后续的报文给丢弃掉,举个例子,TCP的滑动窗口值能够容纳Stream1Stream2的内容,但是现在在TCP线路上并发了Stream1、2、3,这时候因为Stream2和Stream1丢失了,因此滑动窗口停留在初始状态,但是Stream3的内容到达了,但是由于TCP的滑动窗口中没有这个范围的数据,因此Stream3的数据尽管了到达了也会被丢失,白白发送了,这就是TCP队头阻塞的问题

7. HTTP2.0和HTTP3.0的区别?

由于HTTP2.0存在有一个TCP层面的队头阻塞的问题,所以在这样的情况下,HTTP3.0索性将底层的TCP协议替换成了UDP协议

问题:HTTP3.0的底层换用了UDP协议,那么如何来保证传输的可靠性呢?

其实这个问题就是如何基于UDP协议来实现一个可靠的传输协议,可以借鉴一下。

答案是QUIC协议,这个协议有这样的特点:

  • 没有队头阻塞:为什么没有?首先QUIC协议中也有类似于Stream的概念,每一个Stream中包含有若干个message,如果其中一个message丢失了,不会阻塞其他的stream的传输,只会影响本stream,这是因为它底层是UDP实现的,是面向数据报而不是面向字节流的,因此只要对应的包达到了就可以了,而不像TCP协议这样必须保证每个字节都必须按照顺序到达,那么如果丢包了,就会触发当前stream的当前包的重传而已

  • 更快的连接建立:HTTPS的底层如果是TCP连接的话,首先要完成TCP的三次握手,然后再完成SSL/TLS协议的三次握手,但在QUIC协议下,这个握手过程只需要一个RTT,QUIC协议包含了TLS协议,它会在自己的帧中携带TLS中的记录,就相当于在完成QUIC握手的同时,完成了TLS的三次握手,这个过程主要是完成TLS认证的同时也去完成了QUIC的连接ID的确立

  • 连接迁移:上面提到了一个概念叫做连接ID,连接ID是用来标识一对设备的,在TCP中,我们用四元组<本机IP,本机端口,目的IP,目的端口>,只要这四元组中有一个不同,就需要重新建立连接,于是在这样的情况下,如果是TCP连接,比如说本来用WIFI连接的,现在换成流量了,那么就要重新连接,是具备一定连接成本的,但是QUIC不一样,只要本机记住了连接ID,就可以一直用这个连接ID来标识自己,这样的情况下,就不需要重新执行QUIC的三次握手了

8. HTTP用户后续的操作,服务端如何知道属于同一个用户?

首先先说问题所在,HTTP是无状态的协议,服务器不会去记忆HTTP的状态,每次请求到来,它都认为是一个新的请求,这样的话就无法起到记忆的效果了。那么要实现记忆的通常是基于Cookie-Session来实现的。

具体的流程是这样的,客户端向服务器请求登录,验证通过之后,这时候就会在响应的头部打上一个标签,通常是什么JSessionId这样的字样,这其实就是在服务器的底层中,它创建了一个map,然后设置了一个键值对<JSessionId,Object>,这个Object就是Session

然后下次客户端来访问服务器的时候,这时候就会将JSessionId带上发送到服务端,然后服务端就会拿着这个JSessionId就去查底层的map,拿到这个session之后就知道来的人是谁了

9. 如果服务端是一个集群机器?

服务端是一个集群机器,我们上面知道了,存放实体数据的实际上是存放在服务器内存中的session,集群服务器之间内存是不共享的,办法主要有:

引入中间件,比如说redis,设计一个分布式session,这样的话每一个机器就都能够访问redis,也就都能共享你这个session了

先说结论,cookie是存放在客户端的,通常存放在浏览器的缓存(临时)/磁盘(可永久持久化,也可以设置过期时间),它是用来标识服务端上存储的session的,而session是放在服务端中的,通常是存放在服务器的运行内存中,如果服务器重启了,那么就可能导致Session丢失了,需要重新获取

11. 什么是JWT?讲讲原理和校验机制

JWT本身就是无状态的,它包含了身份验证所需要的全部信息,因此服务器就不需要保存session了,这样的话无论你的服务器是否重启,或者中间件服务器是否发生数据丢失,只要客户端存有这个token,就可以完成身份的验证

JWT有三个部分组成,分别是:

  • Header
{
    "alg":"HS256",
    "typ":"JWT"
}

alg:签名的算法,typ:令牌的类型

  • Payload
{
    "userName":"123456"
}

主要包含了一些注册声明和公有声明,私有声明,这个部分默认是不加密的,因此不要将隐私信息存储到这个payload

  • Signature数字签名,主要是防止对前两部分进行篡改,主要的算法就是将HeaderPayload拼在一起,然后用只有服务器知道的密钥,基于签名算法计算出一个签名,如果对方不知道密钥,那么篡改之后得到的签名和用服务端密钥签名所得到的结果肯定是不一样的

JWT实现身份校验的原理是什么?

(1)用户向服务器发送用户名,密码以及验证码用来登录系统

(2)如果用户名和密码正确的话,那么服务端就会签发一个token,也就是JWT

(3)用户以后每次向后端发送请求的时候,都会在Header中带上个JWT

(4)服务端得到这个JWT之后,获取用户端的相关信息

什么是CSRF攻击?

跨站请求伪造,简单来说就是用你的身份去做一些不好的事情,尤其是当你的JWT是存储在你的Cookie中的话,假设你到Cookie中存储了一个银行的JWT,然后在一个非法网站中藏了一个请求,这个请求截取了你的JWT,然后用你的这个JWT去完成转账操作,这样你的钱就被骗走了

JWT这种技术适合在客户端中使用,因为不需要cookie

如何动态刷新JWT?

(1)定期检测更新JWT

服务端给的 JWT 有效期设置为 30 分钟,服务端每次进行校验时,如果发现 JWT 的有效期马上快过期了,服务端就重新生成 JWT 给客户端。客户端每次请求都检查新旧 JWT,如果不一致,则更新本地的 JWT。这种做法的问题是仅仅在快过期的时候请求才会更新 JWT ,对客户端不是很友好。

(2)每次请求都返回新 JWT
这种方案的的思路很简单,但是,开销会比较大,尤其是在服务端要存储维护 JWT 的情况下。

(3)JWT 有效期设置到半夜

这种方案是一种折衷的方案,保证了大部分用户白天可以正常登录,适用于对安全性要求不高的系统。

(4)用户登录返回两个 JWT

第一个是 accessJWT ,它的过期时间就是JWT本身的过期时间比如半个小时

另外一个是 refreshJWT它的过期时间更长一点比如为 1 天。

客户端登录后,将 accessJWT 和 refreshJWT 保存在本地,每次访问将 accessJWT 传给服务端。服务端校验 accessJWT 的有效性,如果过期的话,就将 refreshJWT 传给服务端。如果有效,服务端就生成新的 accessJWT 给客户端。否则,客户端就重新登录即可。

12. 什么是跨域?什么情况下会发生跨域请求?

跨域:浏览器不能够执行其他网站的脚本,它是因为浏览器的同源策略导致的,跨域限制访问,实际上是浏览器的限制

在以下的情况将会发生跨域请求

  • 协议不同,比如说服务端支持的是HTTP请求,而你发送了HTTPS请求
  • 域名不同
  • 端口不同

13. Restful是什么?Restful请求的URl有什么特点

Restful中提供的请求方法中有GetPostPutDelete这四种操作

Rest风格倡导URL地址使用统一的风格设计,从前到后各个单词使用斜杆分开,不使用问号键值对的方式携带参数,而是将要发送给服务器的数据作为数据作为URL地址一部分,以保证整体风格的一致性。

具体的特点可以结合平时开发过程中定义的url进行说明

比如说做一个教务系统,编写一个获取学生的接口,在使用Restful之前的url通常是这样写的

/getStudentById?id=1

而在使用了Restful之后,就将其改成了

/student/1

可以看到特点是参数不用问号键值对的方式携带参数了,而是将要发送给服务器的数据作为URL地址的一部分

特别说明:Get是用来获取数据的(只读)、Put是用来更新数据的(update)、Delete是用来删除数据的,Post通常是用来新增数据的

HTTPS篇

1. HTTP和HTTPS有什么区别?

HTTPHTTPS的区别主要是在于HTTP是不安全的,而HTTPS是安全的,具体的区别如下:

  • HTTP协议无法保证传输的数据是安全的,因为它是明文传输的,只要不法分子具有抓包手段,那么它就能够知道报文中的数据内容,HTTPS因为引入了共享密钥对称加密传输这样的方式,使得只有通信双方才能加密和解密数据
  • HTTP协议无法保证传输的数据是没有被篡改过的,而HTTPS通过摘要技术就可以实现数据的校验
  • HTTP协议无法传输数据的对等端就是目标方,而HTTPS通过CA证书这种方式就可以验证对方的身份
  • HTTP协议的默认端口是80端口,HTTPS的默认协议是443
  • HTTP协议的底层是基于TCP连接的,因此在完成三次握手后就可以传输数据,HTTPS协议的底层是基于TCP+SSL/TLS协议的,因此HTTPS在TCP完成了三次握手之后,还需要完成TLS/SSL握手

2. 了解过哪些加密算法?

(1)对称加密算法(AES加密算法、DES加密算法),这个算法的基本流程是,服务端通过专用信道将共享密钥发送到客户端,在之后的传输中,服务端用这个共享密钥对数据进行加密,然后客户端用这个共享密钥对数据进行解密

(2)非对称加密算法(RSA加密算法),这个算法的基本流程是,服务端通过自己的一套算法计算出一对公钥和私钥,然后将公钥注册到网络上,要注意一点是公钥加密后的数据,只有私钥可以解密,于是在这样的情况下,客户端和服务端就各自有一套公钥和私钥,具体的流程如下:

  • 当服务端要向客户端发送数据的时候,这时候会客户端的公钥对数据进行加密,客户端接收了之后,这时候就会用客户端的私钥进行解密,除非客户端的私钥泄露,否则数据无法被截取解密
  • 当客户端要向服务端发送的数据的时候,这时候会用服务端的公钥对数据进行加密,服务端接收了之后,这时候就会用服务端的私钥进行解密。

3. 对称加密和非对称加密的区别

区别在于使用的密钥方式,对称加密中双方使用的密钥都必须是保密的,而且是相同的,从他们的实现来看,对称加密的运算速度很快

非对称加密中,双方的私钥是必须保密的,公钥是可以公开的,从他们的实现来看,非对称加密的运算速度很慢

4. HTTPS的建立过程是怎么样的?

关于HTTPS的连接建立过程,主要可以分成两个阶段。

第一个阶段主要是要完成底层的TCP连接,也就是三次握手,完成了三次握手之后,就要完成TLS/SSL握手,具体来说是这样的:

(1)ClientHello,首先客户端请求和服务端连接,这时候就会先跟服务端协商HTTPS通信的一些基本事项,比如说有

  • 支持的TLS/SSL协议版本
  • 支持的密码套件
  • 客户端生产的一个随机数

(2)ServerHello,这是服务端对客户端给出的基本事项的一个回应,来表明客户端本次通信要选用哪些套件

  • 支持的TLS/SSL协议版本号,如果服务端不支持客户端的协议版本号的话就直接终止会话
  • 本次通信选用的密码套件,比如说RSA
  • 服务端生产的一个随机数
  • 含有服务端公钥,基本信息的CA证书

(3)ClientReply,这是客户端认证了服务端的身份后给出的回应

  • 验证CA证书,验证完成后,取出公钥

  • 一个pre-master-key,这个是客户端产生的一个随机数,这个随机数会用服务端给出的公钥进行加密传输

  • 通信方式改变通知,表示以后都将用一个对称密钥的方式进行通信

  • 握手结束通知,表示客户端的SSL/TLS握手到此结束,同时会将客户端收到的所有信息做一个摘要,发送给服务端作一个校验

(4)ServerReply,这是服务端计算出来对称密钥之后的一个回应

  • 通过三个随机数,ClientRandomServerRandom、经过解密之后的pre-master-key,计算出对称密钥
  • 通信方式改变通知,表示今后都将用一个对称密钥进行通信
  • 握手结束通知,表示客户端的SSL/TLS握手到此结束了,同时会将服务端收到的所有信息做一个摘要,发送给服务端作一个校验

5. SSL握手流程为什么要用非对称密钥

证明为什么,最好的办法就是反证法,假设SSL握手流程使用的对称密钥,那么会发生什么?

首先在正常的网络传输中,都是使用公开的信道,这就意味着你在网络上传输的数据随时可能被抓包

那么如果使用对称密钥的话,那么前提就是双方都具有这个密钥,那么就要通过网络信道将密钥从对等端传输到对等端了,这就意味着,我们这就将密钥暴露在网络信道上了,这就无法起到保密的作用了

并且,我们使用非对称密钥的方式,就是为了加密对称密钥,现在SSL握手就用加密对称密钥,这不是矛盾了么?

6. 为什么HTTPS不用非对称加密算法加密HTTP报文?

先说结论,这是因为使用非对称加密算法的话,HTTPS的通信就会十分缓慢,因为非对称加密算法的效率是很低的

对于HTTPS这种需要在网络中执行大数据量传输的协议来说,不适合,并且会导致用户的体验很差

其次,对称加密算法的效率是要远高于非对称加密算法的效率的,因此HTTPS的加密策略是:

利用非对称加密算法加密对称密钥,保证对称密钥的安全性,由于对称密钥信息量通常比较小,这时候效率的牺牲是可以接受的,而在之后采用高效的对称加密算法,这时候是很好的

7. HTTPS会对URL进行加密吗?

要理解这个问题,首先于要知道URL是存在哪里的,URL通常是存储在HTTP Header中的,因此是属于HTTP报文的一部分,因此HTTPS会对URL进行加密

8. CA证书绿色是什么意思?什么时候是红色的?什么时候是绿色的?

CA证书是绿色的:它的含义是你的证书通过了验证,那么就会是绿色的

那么它是怎么来验证的呢?首先先来谈谈CA证书的组成,关于CA证书的组成,CA证书的组成有两部分

  • 包含有服务器的基本信息,服务器的公钥等等的一个公开信息表
  • CA的数字签名,当客户端拿到这个签名后就需要验证这个签名了

首先要知道CA机构是如何生成这个签名的,首先它会服务器的基本信息以及公钥这些打成一个包,然后基于一个哈希算法,将这个计算出来的哈希值通过CA的私钥进行加密,就形成了一个数字签名了

只有CA签发的证书才能够被CA公钥所解密

当客户端拿到这个CA证书后,它首先也是会去通过这个服务器的基本信息以及公钥打成一个包,哈希运算后得到一个哈希值,然后同时,用CA的公钥对数字签名进行解密,同样得到一个哈希值,然后对比两个哈希值,如果相同的话,就证明你的这个CA证书是可信的,这时候就是绿色的,否则就是红色的。

9. 自己随便编一个证书可以吗?需要去什么地方注册

不可以,CA证书必须是由CA机构亲自用它的私钥进行加密后产生数字签名后才是有效的,而CA机构的私钥是绝对保密的

TCP篇

1. 说说TCP三次握手的流程

TCP三次握手的流程如下:在初始的时候,服务端和客户端都处于一个关闭的状态,客户端打开,然后服务端被动打开,监听来自客户端的报文,也就是进入一个LISTENING的状态

接着客户端发送一个SYN+c_isn,含义是将发送第一个握手报文,主要是初始化序列号,同时告诉服务端客户端试图和服务端建立连接,这时候客户端进入到了一个SYN_SEND的状态

然后服务端会发送一个SYN+ACK+s_isn,含义是响应客户端的请求,同时将服务端的初始化序列号告诉客户端,这时候服务端进入到了一个SYN_RCVD的状态

当客户端收到这个SYN+ACK之后,此时就进入到了ESTABLISHED的状态,表明可以开始传输数据了,然后客户端就会可以发送数据了,也就是发送ACK,至于带不带数据根据客户端的情况而异

当服务端收到这个ACK之后,就进入到了ESTABLISHED的状态

2. 如果第二次握手丢包会发生什么?

第二次握手的包是SYN+ACK,它的目的主要有

  • 对第一次握手进行确认,是对第一次握手的确认报文
  • 第二次握手中的SYN,是服务端发起建立TCP连接的报文

所以在这样的情况下,会引发两个事件,第一个事件,首先客户端一直没有收到ACK,于是它会认为自己的包丢失,于是会重传第一次的握手报文,第二个事件,由于含有SYN的报文,需要接收一个ACK来确认自己的报文,所以它自己也会重传

当某一个报文的重传达到最大次数限制之后,这时候就会断开连接

3. 如果第三次握手丢包会发生什么?

首先先来分析第三次握手是什么性质的包,第三次握手的包是一个ACK包,因此它是不会主动重传的,所以在这样的情况下,它引发的事件是第二次握手的报文的重传,当重传的次数超过了一定限制之后,这时候就会断开连接

4. 为什么需要三次握手?两次不行吗?

首先从全双工的角度来讲,三次握手可以保证双方都具备了收发能力,分析如下:

第一次握手,什么都不能够确认,客户端不能确保自己发出去的数据能否被接收到,不知道自己是否有发送能力,没有收到数据,不能确定是否有接收能力,服务端没有回传数据,不确定对方是否有接收能力和发送能力

第二次握手,服务端发送出了SYN+ACK,可以确认客户端具有发送能力(可以被服务端收到),同时客户端可以收到服务端的数据,所以客户端具有接收能力,因此进入了ESTABLISHED的状态,而服务端可以确认自己具有接收能力,但无法确认是否具有发送能力,需要客户端发送回包并且被自己收到才能确认

第三次握手,客户端发送ACK能够被服务端收到,那么说明服务端也具有发送能力,具备全双工的条件,进入ESTABLISHED

从解决历史连接的角度来讲,三次握手可以杜绝历史连接分析如下:

这是因为三次握手的条件,产生了一个中间状态,使得服务端可以对那些历史连接做一个重置

假设这样一个场景,就是网络非常阻塞,那么客户端发送了很多次SYN报文,如果只有两次握手的话,那么服务端在收到第二次握手的时候就直接进入了ESTABLISHED的状态,这时候服务端就能够直接发送数据了,但是如果是历史连接的话,那么就白白浪费了网络流量了,这是因为两次握手没有提供一个中间状态来给服务端来断绝这些历史连接

5. TCP四次挥手的过程

四次挥手的流程如下:

我们假设客户端试图关闭连接

(1)客户端发送FIN报文,这时候客户端从ESTABLISHED变成了FIN_WAIT_1,主要是用来告诉服务端,客户端这边的数据传输完成了,关闭发送通道了

(2)服务端接收了FIN报文,这时候服务端从ESTABLISHED变成了CLOSE_WAIT,这是一个缓冲的时间段,这个时间段说的是,服务端那边程序编程中要调用close()函数来处理收尾一些工作,因此是等待服务端程序主动调用close(),在没有调用这个函数之前,都是处于一个CLOSE_WAIT的状态

(3)然后服务端发送收尾数据

(4)发送完毕后,服务端告知客户端,服务端这边的数据发送完毕了,于是发送了FIN报文,这时候服务端就从CLOSE_WAIT状态变成了LAST_ACK,表示等待客户端最后的ACK,确保关闭

(5)客户端收到这个FIN之后,表示知道了对方要关闭连接了,为了防止自己的ACK丢包,对方没有收到这个ACK之前就提前关闭了连接导致了不优雅的关闭,这时候客户端就进入了一个TIME_WAIT状态,表明确实等待对等关闭后自己才关闭

(6)服务端收到这个ACK之后,就关闭了,客户端等待TIME_WAIT结束后,就进入了CLOSE的状态,TCP连接结束

6. 为什么TCP需要四次挥手?三次不行吗?

首先先来分析哪一次挥手能够被省略掉,假设服务端在收到客户端的FIN之后,它本身也没有数据要发送,这时候是可以将FIN+ACK一起发送的,这时候就可以换成三次挥手了,但是一般来说服务端都还要发送收尾数据,于是在这样的情况下,就需要预留一个缓冲时间,因此最终还是设计了三次挥手

7. TIME_WAIT是如何产生的

TIME_WAIT是在主动要求关闭连接的那一段产生的,它主要是为了等待对等端正常退出

8. 为什么需要TIME_WAIT的状态

TIME_WAIT设计出来的用意,主要是为了优雅地关闭TCP连接,尽管处于TIME_WAIT那一端的内核可以提前关闭连接,在后续服务端发送FIN的时候,内核也能够根据报文的上下文来发送RST复位报文,也能够关闭连接,但是这是一种暴力的方式,是不优雅的。

其次,是为了防止历史连接中的数据,被后面相同的四元组的连接错误接收,为了防止错误的序列号被错误接收,假设这样一个场景:

网络拥堵,网络中发送了很多个seq = 301的报文,阻塞在网络中,如果没有TIME_WAIT的状态,然后TCP在后续又开启了同样的连接,如果这时候seq = 301恰好在TCP连接中设定的滑动窗口中,那么这个报文就会被接收,尽管这种现象可以通过时间戳的选项来杜绝,但是在一开始的TCP版本是没有这个时间戳这个选项的,那么设定TIME_WAIT就可以杜绝这个现象,这是TIME_WAIT设定的是2MSL,在这个时间段内,可以保证残留在网络中的本次所有的TCP包都失效被丢弃

9. 服务端产生大量close_wait状态的原因是什么?

close_wait产生的原因主要有:

(1)服务端这边没有主动调用系统调用close()函数执行收尾函数,这就可能导致大量的连接处于close_wait

(2)没有将socket注册到epoll上,这样的话就无法通过事件驱动机制来获取连接的socket,那么就自然无法调用close()了,出现这种现象的原因可能是在将socket注册到epoll之前,抛出了异常

(3)在新连接到来的时候,没有调用accept()

10. 服务端产生大量的TIME_WAIT状态的原因是什么?

TIME_WAIT这个状态是主动关闭连接方才会出现的状态,如果服务器出现大量的TIME_WAIT状态的TCP连接,就是说明服务器主动断开了很多的TCP连接那么一般来说有什么原因呢?

  • HTTP请求没有采用长连接:只要客户端和服务端一方中,这个header中带有Connection:close的话,就会导致短连接

服务端关闭了长连接,那么是谁来主动提出关闭?

假设是客户端主动提出关闭,那么服务端在写完最后一个reponse之后,需要将这个socket放入到readable队列,然后调用select/poll去等待事件,然后调用一次read()才能知道连接被关闭了,这是两次的系统调用

而如果是服务端主动关闭连接,那么服务端在写完最后一个reponse之后,可以直接调用close()就可以释放连接了,剩下的工作交给TCP协议栈即可

客户端关闭了长连接,那么是谁来主动提出关闭?

客户端关闭了长连接,那么意味着客户端在收到请求后,就希望关闭连接,但是客户端并不知道服务端什么时候发送完,所以在这样的情况下,只能将关闭的权利交给服务端

  • HTTP请求超时:当大量的连接超时之后,这时候就会大量的连接主动断开,这时候也会导致大量的TIME_WAIT
  • HTTP请求数量超过了限制

11. TCP的keepalive了解吗?和HTTP的keepalive有什么区别?

TCPkeepalive说的是保活机制,如果两端一直没有数据交互,就达到了触发TCP保活机制的条件,那么内核中的TCP协议栈就会发送探测报文,如果对等程序是正常工作的,那么TCP的保活探测报文就会被发送到对等端,这样TCP的保活时间就会被重置,需要等待下一个TCP保活时间到来

如果对等端的主机宕机了,那么这个探测报文就会石沉大海,达到保活探测次数之后,TCP就会报告这个TCP连接已经关闭了

HTTP的keepalive说的是连接保持机制,当HTTP的Connection设置为Keep-alive的时候,这时候它的底层TCP连接就开启了长连接模式,也就是说一个TCP连接对应多个HTTP连接


文章作者: 穿山甲
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 穿山甲 !
  目录