【20230514】面试题每日打卡-网络相关(一)

158 阅读18分钟

今天是母亲节,和家里人美美的吃了一顿晚饭。虽然现在没有工作,不过家里人还是挺理解我的,也劝我不要太急躁。当然,不急躁不意味着啥都不干,每天规定的学习目标还是要完成的。至于工作嘛,当然也是希望能尽快找到,毕竟手头没代码写确实有点难受,自己想写项目也不知道该写啥......

TCP

TCP和UDP区别

  • TCP面向连接,UDP无连接

  • TCP可靠传输,UDP不可靠(尽最大努力交付)

  • TCP面向字节流,UDP面向报文

TCP三次握手和四次挥手

TCP连接的建立需要三次握手:

  • 第一次握手:客户端向服务器发送SYN报文,表示请求建立连接,并选择一个随机的初始序列号。

  • 第二次握手:服务器收到SYN报文后,向客户端发送SYN+ACK报文,表示同意建立连接,并给出自己的随机序列号。

  • 第三次握手:客户端收到SYN+ACK报文后,向服务器发送ACK报文,表示确认建立连接,并给出自己的序列号。此时,连接建立成功,双方开始传输数据。

上述每一次握手的作用如下:

  • 第一次握手:客户端发送网络包,服务端收到了 这样服务端就能得出结论:客户端的发送能力、服务端的接收能力是正常的。
  • 第二次握手:服务端发包,客户端收到了 这样客户端就能得出结论:服务端的接收、发送能力,客户端的接收、发送能力是正常的。不过此时服务器并不能确认客户端的接收能力是否正常
  • 第三次握手:客户端发包,服务端收到了。 这样服务端就能得出结论:客户端的接收、发送能力正常,服务器自己的发送、接收能力也正常

通过三次握手,就能确定双方的接收和发送能力是正常的。之后就可以正常通信了。

TCP连接断开,需要四次挥手:

  • 第一次挥手:客户端向服务器发送FIN报文,表示请求关闭连接。

  • 第二次挥手:服务器收到FIN报文后,向客户端发送ACK报文,表示已经收到了客户端的请求。

  • 第三次挥手:服务器向客户端发送FIN报文,表示自己的数据已经传输完毕,请求关闭连接。

  • 第四次挥手:客户端收到FIN报文后,向服务器发送ACK报文,表示已经收到了服务器的请求。

四次挥手的设计是为了确保在数据传输结束后,双方的连接可以安全地关闭,释放资源。在挥手过程中,第一次挥手是客户端请求关闭连接,第二次挥手是服务器确认请求,第三次挥手是服务器请求关闭连接,第四次挥手是客户端确认请求。这样的设计可以防止双方同时发送请求、重复请求等问题,保证连接的安全性和可靠性。

HTTP

历代版本特性

每一代的HTTP都在上一代的基础上增加功能和优化性能。

  • HTTP1.0:仅支持getpost两种格式的请求;

  • HTTP1.1

    • 在1.0的基础上支持了长连接Connection: keep-alive,即在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟;

    • 引入了更多的缓存控制策略,如If-Unmodified-Since, If-Match, If-None-Match等缓存头来控制缓存策略;

    • 引入range,允许值请求资源某个部分;

    • 引入host,实现了在一台WEB服务器上可以在同一个IP地址和端口号上使用不同的主机名来创建多个虚拟WEB站点;

    • 增加了其他请求方法,如:optionsputdelete...

  • HTTP/2

    • 使用多路复用让TCP连接一次进行多次请求与响应;

    • 使用二进制分帧的形式取代文本格式进行数据传输;

    • 通过首部压缩来减少冗余数据的传输、允许服务端推送资源给客户端。

  • HTTP/3

    • 基于QUIC

      • QUIC基于UDP,彻底解决之前基于TCP的队头阻塞问题;

      • 一次握手:由于QUIC的设计,HTTP/3 可以更快地建立连接。在TCP + TLS 中,新的连接需要两轮握手才能建立,而在 QUIC 中,只需要一轮握手;

      • QUIC协议内置了TLS,这意味着所有的HTTP/3连接都是安全的,无需额外的加密步骤;

      • 支持所谓的“无连接迁移”,这意味着如果用户的网络环境改变(例如,从Wi-Fi切换到 4G),HTTP/3连接可以无缝切换,而无需重新建立。

状态码

如果根据状态码的前缀进行分类,有如下几种:

  • 1xx - Informational:请求已被服务器接收,继续处理。

  • 2xx - Success:请求已成功被服务器接收、理解、并接受。

    • 200 - OK:请求成功

    • 201 - Created:请求并创建了新的资源

    • 204 - No Content:请求已成功处理,但没有返回响应正文。

  • 3xx - Redirection:需要客户端采取进一步的操作才能完成请求。

    • 301 - Moved Permanently:永久重定向,请求的URL已永久移动到新的位置

    • 302 - Found:临时重定向,请求的资源已被分配了新的URI,希望用户本次能使用新的URI访问。

    • 304 - Not Modified:表示客户端发送附带条件请求时,服务器端允许请求访问资源,但未满足条件的情况。(一般用于协商缓存校验:服务器收到请求,将服务器的中此文件的 ETag,跟请求头中的 If-None-Match 相比较,如果值是一样的,说明缓存还是最新的,Web 服务器将发送 304 Not Modified 响应码给客户端表示缓存未修改过,可以使用。)

  • 4xx - Client Error:请求包含语法错误或无法完成请求。

    • 400 - Bad Request:请求包含语法错误或无法完成请求。

    • 401 - Unauthorized:请求需要身份验证,客户端需要提供凭据。

    • 403 - Forbidden:服务器拒绝执行请求,客户端没有权限。

    • 404 - Not Found:服务器无法找到请求的URL。

  • 5xx - Server Error:服务器在处理请求时发生错误。

    • 500 - Internal Server Error:服务器在处理请求时发生了错误。

    • 503 - Service Unavailable:服务器当前无法处理请求,因为过载或正在维护。

HTTP缓存

HTTP缓存根据是否需要重新向服务器发起请求来分类,可分为强缓存和协商缓存。

强制缓存在缓存数据未失效的情况下(即Cache-Controlmax-age没有过期或者Expires的缓存时间没有过期),那么就会直接使用浏览器的缓存数据,不会再向服务器发送任何请求。强制缓存生效时,http状态码为200。这种方式页面的加载速度是最快的,性能也是很好的,但是在这期间,如果服务器端的资源修改了,页面上是拿不到的,因为它不会再向服务器发请求了。 跟强制缓存相关的header头属性有(Pragma/Cache-Control/Expires),当PragmaCache-control共存时,Pragma的优先级是比Cache-Control高的。

当第一次请求时服务器返回的响应头中没有Cache-ControlExpires或者Cache-ControlExpires过期还或者它的属性设置为no-cache时(即不走强缓存),那么浏览器第二次请求时就会与服务器进行协商,与服务器端对比判断资源是否进行了修改更新。如果服务器端的资源没有修改,那么就会返回304状态码,告诉浏览器可以使用缓存中的数据,这样就减少了服务器的数据传输压力。如果数据有更新就会返回200状态码,服务器就会返回更新后的资源并且将缓存信息一起返回。跟协商缓存相关的header头属性有(ETag/If-Not-Match 、Last-Modified/If-Modified-Since

一言以蔽之,强缓存只要缓存一次就一直用到过期为止,不管资源更新的事情;而协商缓存在使用前则需要发请求校验本地缓存是否需要更新。

HTTPS

关于HTTPS知识的要点有三个:信息加密、完整性校验、身份验证。理解每个要点是如何实现的就可以了。

信息加密

HTTPS采用对称加密+非对称加密传输数据,先用非对称加密进行对称加密密钥的传输,再用这个对称加密密钥进行对称加密传输数据。所谓对称加密,指的是加密和解密使用的秘钥都是同一个,是对称的;而非对称加密则存在两个不同的秘钥,一个叫公钥,一个叫私钥。公钥可以公开给任何人使用,私钥则需要保密。公钥加密后只能用私钥解密,反过来,私钥加密后也只能用公钥解密。

不过在网络传输过程中,数据有可能被篡改,并且黑客可以伪造身份发布公钥。所以HTTPS传输还需要保证数据不被篡改。

完整性校验

HTTPS实现保障数据完整不被篡改的方式是使用摘要算法。简单理解的话,摘要算法是一种特殊的压缩算法,它能够把任意长度的数据“压缩”成固定长度、而且独一无二的字符串。在原文附上摘要后,接收端只需要用同样的方式对接收到的原文生成摘要,与传送过来的摘要进行对比,就可以知道数据有没有被篡改了。

身份认证

如果公钥真实性得不到保证,前面做的两件事情其实都没啥用。这时候我们需要客户端和服务端双方都信赖的数字证书认证机构(CA)来担保公钥的真实性。服务器的公钥在登录至数字认证机构之后,数字证书认证机构为服务器颁发证书(服务器的公开密钥+CA的数字签名);当客户端收到服务端发来的数字证书时,可以通过CA的公开密钥(浏览器内置)来验证公钥是否真实。

DNS解析

获取目标IP采用的算法

DNS解析使用的算法有两种:

  • 迭代查询算法:本地DNS服务器向根DNS服务器查询,得到顶级域的DNS服务器的IP地址,再向顶级域的DNS服务器查询,得到权威DNS服务器的IP地址,最终得到域名对应的IP地址。这种算法是逐级查询的过程,每一步都需要等待上一步返回结果后才能进行下一步查询。

  • 递归查询算法:本地DNS服务器向根DNS服务器查询,得到顶级域的DNS服务器的IP地址,并向顶级域的DNS服务器查询,得到权威DNS服务器的IP地址,并将查询结果返回给本地DNS服务器。这种算法是本地DNS服务器向其他DNS服务器进行查询,并等待其他DNS服务器返回结果的过程,本地DNS服务器会一直等待直到得到查询结果。

具体工作过程

  1. 检查本地缓存:先检查本地计算机是否有该域名对应的IP地址,如果有,则直接返回该IP地址,不再进行后续查询过程。

  2. 发送请求到本地DNS服务器:如果本地计算机中没有该域名对应的IP地址,则向本地DNS服务器发送查询请求。

  3. 本地DNS服务器查询缓存:本地DNS服务器会先检查自己的缓存中是否有该域名对应的IP地址,如果有,则直接返回该IP地址。

  4. 本地DNS服务器向根DNS服务器查询:如果本地DNS服务器中没有该域名对应的IP地址,则向根DNS服务器发送查询请求。

  5. DNS服务器向顶级DNS服务器查询:根DNS服务器会返回一个顶级域的DNS服务器的IP地址,本地DNS服务器会向该顶级DNS服务器发送查询请求。

  6. 顶级DNS服务器向权威DNS服务器查询:顶级DNS服务器会返回一个权威DNS服务器的IP地址,本地DNS服务器会向该权威DNS服务器发送查询请求。

  7. 权威DNS服务器返回IP地址:权威DNS服务器中保存有该域名对应的IP地址,会将该IP地址返回给本地DNS服务器。

  8. 本地DNS服务器将IP地址返回给计算机:本地DNS服务器会将该IP地址保存在缓存中,并将该IP地址返回给本地计算机,以便进行下一步的通信。

前端安全

XSS

xss跨站脚本攻击指的是攻击者利用Web应用程序中的漏洞,向网站注入恶意脚本,使得在用户浏览网站时,恶意脚本被执行,从而导致攻击者能够获取用户的敏感信息或者进行一些恶意操作。

既然其执行机理是在被攻击者的浏览器中执行脚本,那么我们就要关心一下攻击者是如何注入脚本的。从这个点出发去思考,如果对XSS攻击来源进行分类,有以下几种:

  • 存储型XSS:攻击者通过将恶意脚本注入数据库,当被攻击者访问网站时恶意脚本被读取执行。这种攻击常见于带有用户保存数据的网站功能,如论坛发帖、商品评论、用户私信等。

  • 反射型XSS:攻击者通过URL携带恶意脚本,被攻击者点击URL访问网站就中招了。这种攻击常见于通过 URL 传递参数的功能,如网站搜索、跳转等。由于需要用户主动打开恶意的 URL 才能生效,攻击者往往会结合多种手段诱导用户点击(比如一刀999真传奇、澳门皇家xx性感xx在线发牌等)。

  • DOMXSS:区别于反射型XSS,这种攻击方式不是利用服务端漏洞进行攻击,而是利用前端代码的漏洞来攻击的。前端代码去解析URL传递的参数导致误执行恶意脚本,从而使攻击者得逞。

预防手段也是有的,不过这里只聊聊前端的注意事项:

CSRF

跨站请求伪造(CSRF)指的是攻击者诱导受害者进入第三方网站,在第三方网站中,向被攻击网站发送跨站请求。通过这种方式,攻击者可以利用受害者在被攻击网站已经获取的注册凭证,绕过后台的用户验证,达到冒充用户对被攻击的网站执行某项操作的目的。

其核心攻击流程就是在用户不知情的情况下请求其他网站,导致用户本身的登录凭据等在cookies中的信息被恶意使用。

防范csrf攻击可以有以下几个思路:

  • 使用随机令牌:在每个表单提交中,生成一个随机令牌,并将该令牌存储在用户的会话中。在表单提交时,验证该令牌是否与会话中的令牌匹配。这样可以确保提交表单的用户是在您的应用程序中进行操作的真正用户。

  • 检查来源头:在服务器端,检查每个请求的来源头,确保它来自您的应用程序,而不是其他网站。这可以通过验证来源头中的域名来实现。从Chrome 51开始,浏览器的 Cookie新增加了一个SameSite属性,主要用于防止CSRF攻击和用户追踪。更加详尽的解析可以看Cookie Samesite简析 - 知乎open in new window

  • 在敏感操作(如更改密码、删除帐户等)之前,要求用户输入验证码。这可以确保只有真正的用户才能执行这些操作。

  • 避免使用GET请求:GET请求可以轻松地被劫持并被篡改,因此避免使用它们来执行敏感操作。

其他问题

浏览器访问网址过程发生了什么

老生常谈的问题,具体回答的内容可以涉及以下的要点:

  • 输入url发起请求,首先进行域名解析(DNS解析过程)

  • 域名解析的结果可以是源主机IP,也可以是CDN加速的CNAME,如果是CNAME,本地DNS服务器会去请求CNAME对应地址,从而获取CDN智能调度分配的IP

  • 建立HTTP连接(TCP三次握手和四次挥手、HTTPSSSL/TLS握手)

  • 客户端获取资源的细节(HTTP缓存)

  • 客户端渲染页面的过程(解析HTML标签、构建DOM/CSSOM树、合成渲染树、计算样式、布局、绘制等步骤)

GET和POST的区别

  • 参数携带方式不同:GET只能把参数放在URL里(因此也有数据长度限制),POST可以放入body中,因此可以发送更大的数据,而且比GET更安全

  • 幂等性:所谓幂等,即多次请求,服务端状态不变。所以GET是幂等的,POST不是幂等的。

  • 用途不同:GET一般用于获取/查询资源信息,而POST一般用于更新资源信息。

  • 缓存:GET请求默认可以被缓存,也可以被添加到书签,或者在浏览历史中保存;而POST请求不会被缓存,也不会添加到书签,也不会在浏览历史中保存。

fetch发送两次请求的原因

如果你在使用fetch API发送请求时发现它发送了两次请求,那可能是因为你使用了CORS(跨源资源共享)策略,并且你的请求满足了预检(preflight)请求的条件。

这是由于浏览器的安全策略决定的。当你试图执行某些类型的跨域HTTP请求时,浏览器会首先使用OPTIONS方法发出一个预检请求到服务器,以确认真实请求是否安全被服务器接收。这个预检请求就是可能导致你看到两个请求的原因。

预检请求主要用于带有一些特定参数的HTTP请求,例如:

  • 使用了除GETHEADPOST之外的方法,如PUTDELETE等;
  • POST请求的Content-Type不是application/x-www-form-urlencodedmultipart/form-datatext/plain
  • 请求包含了自定义的headers

如果你的请求满足上述任何一个条件,浏览器就会先发送一个预检请求。只有当预检请求成功,服务器返回适当的CORS headers之后,浏览器才会发送实际的HTTP请求。

跨域问题及其解决方案

跨域问题的本质就是浏览器的同源策略导致的。"同源"的判断依据是协议、域名和端口三者都必须相同。只要有一个不同,就被视为跨域。要解决这个问题,我们可以选择遵守它或者绕开它。下面是比较常用的几种解决方案:

  • 服务器支持:设置响应头Access-Control-Allow-Origin

  • JSONP:本质是通过动态添加一个script标签,通过src属性去请求服务端,响应内容通过callback进行获取

  • 反向代理:Webpackproxynginxproxy-pass