计算机网络
计算机网络基础
网络分层模型
常见网络协议
- HTTP(Hypertext Transfer Protocol,超文本传输协议):基于 TCP 协议,是一种用于传输超文本和多媒体内容的协议,主要是为 Web 浏览器与 Web 服务器之间的通信而设计的。当我们使用浏览器浏览网页的时候,我们网页就是通过 HTTP 请求进行加载的。
- SMTP(Simple Mail Transfer Protocol,简单邮件发送协议):基于 TCP 协议,是一种用于发送电子邮件的协议。注意 ⚠️:SMTP 协议只负责邮件的发送,而不是接收。要从邮件服务器接收邮件,需要使用 POP3 或 IMAP 协议。
- POP3/IMAP(邮件接收协议):基于 TCP 协议,两者都是负责邮件接收的协议。IMAP 协议是比 POP3 更新的协议,它在功能和性能上都更加强大。IMAP 支持邮件搜索、标记、分类、归档等高级功能,而且可以在多个设备之间同步邮件状态。几乎所有现代电子邮件客户端和服务器都支持 IMAP。
- FTP(File Transfer Protocol,文件传输协议) : 基于 TCP 协议,是一种用于在计算机之间传输文件的协议,可以屏蔽操作系统和文件存储方式。注意 ⚠️:FTP 是一种不安全的协议,因为它在传输过程中不会对数据进行加密。建议在传输敏感数据时使用更安全的协议,如 SFTP。
- Telnet(远程登陆协议):基于 TCP 协议,用于通过一个终端登陆到其他服务器。Telnet 协议的最大缺点之一是所有数据(包括用户名和密码)均以明文形式发送,这有潜在的安全风险。这就是为什么如今很少使用 Telnet,而是使用一种称为 SSH 的非常安全的网络传输协议的主要原因。
- SSH(Secure Shell Protocol,安全的网络传输协议):基于 TCP 协议,通过加密和认证机制实现安全的访问和文件传输等业务
- RTP(Real-time Transport Protocol,实时传输协议):通常基于 UDP 协议,但也支持 TCP 协议。它提供了端到端的实时传输数据的功能,但不包含资源预留存、不保证实时传输质量,这些功能由 WebRTC 实现。
- DNS(Domain Name System,域名管理系统): 基于 UDP 协议,用于解决域名和 IP 地址的映射问题。
传输层协议
- TCP(Transmission Control Protocol,传输控制协议 ):提供 面向连接 的,可靠 的数据传输服务。
- UDP(User Datagram Protocol,用户数据协议):提供 无连接 的,尽最大努力 的数据传输服务(不保证数据传输的可靠性),简单高效。
网络层协议
- IP(Internet Protocol,网际协议):TCP/IP 协议中最重要的协议之一,属于网络层的协议,主要作用是定义数据包的格式、对数据包进行路由和寻址,以便它们可以跨网络传播并到达正确的目的地。目前 IP 协议主要分为两种,一种是过去的 IPv4,另一种是较新的 IPv6,目前这两种协议都在使用,但后者已经被提议来取代前者。
- ARP(Address Resolution Protocol,地址解析协议):ARP 协议解决的是网络层地址和链路层地址之间的转换问题。因为一个 IP 数据报在物理上传输的过程中,总是需要知道下一跳(物理上的下一个目的地)该去往何处,但 IP 地址属于逻辑地址,而 MAC 地址才是物理地址,ARP 协议解决了 IP 地址转 MAC 地址的一些问题。
- ICMP(Internet Control Message Protocol,互联网控制报文协议):一种用于传输网络状态和错误消息的协议,常用于网络诊断和故障排除。例如,Ping 工具就使用了 ICMP 协议来测试网络连通性。
- NAT(Network Address Translation,网络地址转换协议):NAT 协议的应用场景如同它的名称——网络地址转换,应用于内部网到外部网的地址转换过程中。具体地说,在一个小的子网(局域网,LAN)内,各主机使用的是同一个 LAN 下的 IP 地址,但在该 LAN 以外,在广域网(WAN)中,需要一个统一的 IP 地址来标识该 LAN 在整个 Internet 上的位置。
- OSPF(Open Shortest Path First,开放式最短路径优先):一种内部网关协议(Interior Gateway Protocol,IGP),也是广泛使用的一种动态路由协议,基于链路状态算法,考虑了链路的带宽、延迟等因素来选择最佳路径。
- RIP(Routing Information Protocol,路由信息协议):一种内部网关协议(Interior Gateway Protocol,IGP),也是一种动态路由协议,基于距离向量算法,使用固定的跳数作为度量标准,选择跳数最少的路径作为最佳路径。
- BGP(Border Gateway Protocol,边界网关协议):一种用来在路由选择域之间交换网络层可达性信息(Network Layer Reachability Information,NLRI)的路由选择协议,具有高度的灵活性和可扩展性。
HTTP
从输入 URL 到页面展示到底发生了什么?(非常重要)
- 在浏览器中输入指定网页的 URL。
- 浏览器通过 DNS 协议,获取域名对应的 IP 地址。
- 浏览器根据 IP 地址和端口号,向目标服务器发起一个 TCP 连接请求。
- 浏览器在 TCP 连接上,向服务器发送一个 HTTP 请求报文,请求获取网页的内容。
- 服务器收到 HTTP 请求报文后,处理请求,并返回 HTTP 响应报文给浏览器。
- 浏览器收到 HTTP 响应报文后,解析响应体中的 HTML 代码,渲染网页的结构和样式,同时根据 HTML 中的其他资源的 URL(如图片、CSS、JS 等),再次发起 HTTP 请求,获取这些资源的内容,直到网页完全加载显示。
- 浏览器在不需要和服务器通信时,可以主动关闭 TCP 连接,或者等待服务器的关闭请求。
HTTP Header 中常见的字段有哪些?
字段 | 说明 |
---|---|
Host | 指定请求的主机名和端口号,用于区分不同的域名或虚拟主机。 |
User-Agent | 包含发起请求的客户端软件信息(如浏览器、操作系统等)。 |
Accept | 指定客户端能够接收的内容类型(如 text/html , application/json )。 |
Accept-Language | 指定客户端的语言偏好(如 en-US , zh-CN )。 |
Accept-Encoding | 指定客户端能够理解的内容编码(如 gzip , deflate ),用于压缩数据。 |
Content-Type | 指定请求或响应的内容类型(如 application/json , text/html )。 |
Content-Length | 指定请求或响应的内容长度(以字节为单位)。 |
Authorization | 携带认证凭证,用于身份验证(如 Bearer token )。 |
Cookie | 客户端发送的Cookie信息,用于会话保持。 |
Set-Cookie | 服务器设置Cookie的信息,用于会话管理或状态保存。 |
Referer | 指定请求的来源页面的URL,用于追踪请求来源。 |
Location | 指定重定向的URL地址,通常在状态码3xx响应中使用。 |
Cache-Control | 用于指定缓存策略(如 no-cache , max-age=3600 )。 |
Expires | 指定资源的过期时间,用于缓存管理。 |
ETag | 资源的唯一标识符,常用于缓存验证。 |
Last-Modified | 资源的最后修改时间,常用于缓存验证。 |
Connection | 指定连接的管理方式(如 keep-alive , close )。 |
Transfer-Encoding | 指定传输编码方式(如 chunked ),用于分块传输响应数据。 |
Content-Encoding | 指定内容的编码方式(如 gzip ),用于压缩响应数据。 |
Origin | 指定请求的来源域名,用于跨域资源共享(CORS)请求。 |
Access-Control-Allow-Origin | 指定允许哪些源访问资源,用于CORS响应头。 |
X-Forwarded-For | 指定客户端的原始IP地址,通常用于代理服务器转发请求。 |
X-Frame-Options | 指定是否允许页面在 <iframe> 中显示(如 DENY , SAMEORIGIN ),用于防范点击劫持。 |
HTTP 和 HTTPS 有什么区别?
- 端口号:HTTP 默认是 80,HTTPS 默认是 443。
- URL 前缀:HTTP 的 URL 前缀是
http://
,HTTPS 的 URL 前缀是https://
。 - 安全性和资源消耗:HTTP 协议运行在 TCP 之上,所有传输的内容都是明文,客户端和服务器端都无法验证对方的身份。HTTPS 是运行在 SSL/TLS 之上的 HTTP 协议,SSL/TLS 运行在 TCP 之上。所有传输的内容都经过加密,加密采用对称加密,但对称加密的密钥用服务器方的证书进行了非对称加密。所以说,HTTP 安全性没有 HTTPS 高,但是 HTTPS 比 HTTP 耗费更多服务器资源。
- SEO(搜索引擎优化):搜索引擎通常会更青睐使用 HTTPS 协议的网站,因为 HTTPS 能够提供更高的安全性和用户隐私保护。使用 HTTPS 协议的网站在搜索结果中可能会被优先显示,从而对 SEO 产生影响。
HTTP/1.0 和 HTTP/1.1 有什么区别?
- 连接方式 : HTTP/1.0 为短连接,HTTP/1.1 支持长连接。HTTP 协议的长连接和短连接,实质上是 TCP 协议的长连接和短连接。
- 状态响应码 : HTTP/1.1 中新加入了大量的状态码,光是错误响应状态码就新增了 24 种。比如说,
100 (Continue)
——在请求大资源前的预热请求,206 (Partial Content)
——范围请求的标识码,409 (Conflict)
——请求与当前资源的规定冲突,410 (Gone)
——资源已被永久转移,而且没有任何已知的转发地址。 - 缓存机制 : 在 HTTP/1.0 中主要使用 Header 里的 If-Modified-Since,Expires 来做为缓存判断的标准,HTTP/1.1 则引入了更多的缓存控制策略例如 Entity tag,If-Unmodified-Since, If-Match, If-None-Match 等更多可供选择的缓存头来控制缓存策略。
- 带宽:HTTP/1.0 中,存在一些浪费带宽的现象,例如客户端只是需要某个对象的一部分,而服务器却将整个对象送过来了,并且不支持断点续传功能,HTTP/1.1 则在请求头引入了 range 头域,它允许只请求资源的某个部分,即返回码是 206(Partial Content),这样就方便了开发者自由的选择以便于充分利用带宽和连接。
- Host 头(Host Header)处理 :HTTP/1.1 引入了 Host 头字段,允许在同一 IP 地址上托管多个域名,从而支持虚拟主机的功能。而 HTTP/1.0 没有 Host 头字段,无法实现虚拟主机。
HTTP/1.1 和 HTTP/2.0 有什么区别?
- 多路复用(Multiplexing):HTTP/2.0 在同一连接上可以同时传输多个请求和响应(可以看作是 HTTP/1.1 中长链接的升级版本),互不干扰。HTTP/1.1 则使用串行方式,每个请求和响应都需要独立的连接,而浏览器为了控制资源会有 6-8 个 TCP 连接的限制。。这使得 HTTP/2.0 在处理多个请求时更加高效,减少了网络延迟和提高了性能。
- 二进制帧(Binary Frames):HTTP/2.0 使用二进制帧进行数据传输,而 HTTP/1.1 则使用文本格式的报文。二进制帧更加紧凑和高效,减少了传输的数据量和带宽消耗。
- 头部压缩(Header Compression):HTTP/1.1 支持
Body
压缩,Header
不支持压缩。HTTP/2.0 支持对Header
压缩,使用了专门为Header
压缩而设计的 HPACK 算法,减少了网络开销。 服务器推送(Server Push):HTTP/2.0 支持服务器推送,可以在客户端请求一个资源时,将其他相关资源一并推送给客户端,从而减少了客户端的请求次数和延迟。而 HTTP/1.1 需要客户端自己发送请求来获取相关资源。
HTTP/2.0 和 HTTP/3.0 有什么区别?
- 传输协议:HTTP/2.0 是基于 TCP 协议实现的,HTTP/3.0 新增了 QUIC(Quick UDP Internet Connections) 协议来实现可靠的传输,提供与 TLS/SSL 相当的安全性,具有较低的连接和传输延迟。你可以将 QUIC 看作是 UDP 的升级版本,在其基础上新增了很多功能比如加密、重传等等。HTTP/3.0 之前名为 HTTP-over-QUIC,从这个名字中我们也可以发现,HTTP/3 最大的改造就是使用了 QUIC。
- 连接建立:HTTP/2.0 需要经过经典的 TCP 三次握手过程(由于安全的 HTTPS 连接建立还需要 TLS 握手,共需要大约 3 个 RTT)。由于 QUIC 协议的特性(TLS 1.3,TLS 1.3 除了支持 1 个 RTT 的握手,还支持 0 个 RTT 的握手)连接建立仅需 0-RTT 或者 1-RTT。这意味着 QUIC 在最佳情况下不需要任何的额外往返时间就可以建立新连接。
- 头部压缩:HTTP/2.0 使用 HPACK 算法进行头部压缩,而 HTTP/3.0 使用更高效的 QPACK 头压缩算法。
- 队头阻塞:HTTP/2.0 多请求复用一个 TCP 连接,一旦发生丢包,就会阻塞住所有的 HTTP 请求。由于 QUIC 协议的特性,HTTP/3.0 在一定程度上解决了队头阻塞(Head-of-Line blocking, 简写:HOL blocking)问题,一个连接建立多个不同的数据流,这些数据流之间独立互不影响,某个数据流发生丢包了,其数据流不受影响(本质上是多路复用+轮询)。
- 连接迁移:HTTP/3.0 支持连接迁移,因为 QUIC 使用 64 位 ID 标识连接,只要 ID 不变就不会中断,网络环境改变时(如从 Wi-Fi 切换到移动数据)也能保持连接。而 TCP 连接是由(源 IP,源端口,目的 IP,目的端口)组成,这个四元组中一旦有一项值发生改变,这个连接也就不能用了。
- 错误恢复:HTTP/3.0 具有更好的错误恢复机制,当出现丢包、延迟等网络问题时,可以更快地进行恢复和重传。而 HTTP/2.0 则需要依赖于 TCP 的错误恢复机制。
- 安全性:在 HTTP/2.0 中,TLS 用于加密和认证整个 HTTP 会话,包括所有的 HTTP 头部和数据负载。TLS 的工作是在 TCP 层之上,它加密的是在 TCP 连接中传输的应用层的数据,并不会对 TCP 头部以及 TLS 记录层头部进行加密,所以在传输的过程中 TCP 头部可能会被攻击者篡改来干扰通信。而 HTTP/3.0 的 QUIC 对整个数据包(包括报文头和报文体)进行了加密与认证处理,保障安全性。
- HTTP/2.0:使用 TCP 作为传输协议、使用 HPACK 进行头部压缩、依赖 TLS 进行加密。
- HTTP/3.0:使用基于 UDP 的 QUIC 协议、使用更高效的 QPACK 进行头部压缩、在 QUIC 中直接集成了 TLS。QUIC 协议具备连接迁移、拥塞控制与避免、流量控制等特性。
HTTP 是不保存状态的协议, 如何保存用户状态?
HTTP 是一种不保存状态,即无状态(stateless)协议。也就是说 HTTP 协议自身不对请求和响应之间的通信状态进行保存。
Session 机制的存在就是为了解决这个问题,Session 的主要作用就是通过服务端记录用户的状态。
典型的场景是购物车,当你要添加商品到购物车的时候,系统不知道是哪个用户操作的,因为 HTTP 协议是无状态的。
服务端给特定的用户创建特定的 Session 之后就可以标识这个用户并且跟踪这个用户了(一般情况下,服务器会在一定时间内保存这个 Session,过了时间限制,就会销毁这个 Session)。
在服务端保存 Session 的方法很多,最常用的就是内存和数据库(比如是使用内存数据库 redis 保存)。既然 Session 存放在服务器端,那么我们如何实现 Session 跟踪呢?大部分情况下,我们都是通过在 Cookie 中附加一个 Session ID 来方式来跟踪。
Cookie 被禁用怎么办?
最常用的就是利用 URL 重写把 Session ID 直接附加在 URL 路径的后面。
URI 和 URL 的区别是什么
- URI(Uniform Resource Identifier) 是统一资源标志符,可以唯一标识一个资源。
- URL(Uniform Resource Locator) 是统一资源定位符,可以提供该资源的路径。它是一种具体的 URI,即 URL 可以用来标识一个资源,而且还指明了如何 locate 这个资源。
URI 的作用像身份证号一样,URL 的作用更像家庭住址一样。URL 是一种具体的 URI,它不仅唯一标识资源,而且还提供了定位该资源的信息。
GET 和 POST 的区别
- 语义(主要区别):GET 通常用于获取或查询资源,而 POST 通常用于创建或修改资源。
- 幂等:GET 请求是幂等的,即多次重复执行不会改变资源的状态,而 POST 请求是不幂等的,即每次执行可能会产生不同的结果或影响资源的状态。
- 格式:GET 请求的参数通常放在 URL 中,形成查询字符串(querystring),而 POST 请求的参数通常放在请求体(body)中,可以有多种编码格式,如 application/x-www-form-urlencoded、multipart/form-data、application/json 等。GET 请求的 URL 长度受到浏览器和服务器的限制,而 POST 请求的 body 大小则没有明确的限制。不过,实际上 GET 请求也可以用 body 传输数据,只是并不推荐这样做,因为这样可能会导致一些兼容性或者语义上的问题。
- 缓存:由于 GET 请求是幂等的,它可以被浏览器或其他中间节点(如代理、网关)缓存起来,以提高性能和效率。而 POST 请求则不适合被缓存,因为它可能有副作用,每次执行可能需要实时的响应。
- 安全性:GET 请求和 POST 请求如果使用 HTTP 协议的话,那都不安全,因为 HTTP 协议本身是明文传输的,必须使用 HTTPS 协议来加密传输数据。另外,GET 请求相比 POST 请求更容易泄露敏感数据,因为 GET 请求的参数通常放在 URL 中。
Cookie 和 Session
Cookie 和 Session 有什么区别?
Cookie
存放在客户端,一般用来保存用户信息。Session
的主要作用就是通过服务端记录用户的状态。
如何使用 Session-Cookie 方案进行身份验证?
- 用户成功登陆系统,然后返回给客户端具有
SessionID
的Cookie
。 - 当用户向后端发起请求的时候会把
SessionID
带上,这样后端就知道你的身份状态了。
- 用户向服务器发送用户名、密码、验证码用于登陆系统。
- 服务器验证通过后,服务器为用户创建一个
Session
,并将Session
信息存储起来。 - 服务器向用户返回一个
SessionID
,写入用户的Cookie
。 - 当用户保持登录状态时,
Cookie
将与每个后续请求一起被发送出去。 - 服务器可以将存储在
Cookie
上的SessionID
与存储在内存中或者数据库中的Session
信息进行比较,以验证用户的身份,返回给用户客户端响应信息的时候会附带用户当前的状态。
多服务器节点下 Session-Cookie 方案
- 某个用户的所有请求都通过特性的哈希策略分配给同一个服务器处理。这样的话,每个服务器都保存了一部分用户的 Session 信息。服务器宕机,其保存的所有 Session 信息就完全丢失了。
- 每一个服务器保存的 Session 信息都是互相同步的,也就是说每一个服务器都保存了全量的 Session 信息。每当一个服务器的 Session 信息发生变化,我们就将其同步到其他服务器。这种方案成本太大,并且,节点越多时,同步成本也越高。
- 单独使用一个所有服务器都能访问到的数据节点(比如缓存)来存放 Session 信息。为了保证高可用,数据节点尽量要避免是单点。
- Spring Session 是一个用于在多个服务器之间管理会话的项目。它可以与多种后端存储(如 Redis、MongoDB 等)集成,从而实现分布式会话管理。通过 Spring Session,可以将会话数据存储在共享的外部存储中,以实现跨服务器的会话同步和共享。
如果没有 Cookie 的话 Session 还能用吗?
一般是通过 Cookie
来保存 SessionID
,假如你使用了 Cookie
保存 SessionID
的方案的话, 如果客户端禁用了 Cookie
,那么 Session
就无法正常工作。
但是,并不是没有 Cookie
之后就不能用 Session
了,比如你可以将 SessionID
放在请求的 url
里面https://blog.kanes.top/?Session_id=xxx
。这种方案的话可行,但是安全性和用户体验感降低。当然,为了安全你也可以对 SessionID
进行一次加密之后再传入后端。
为什么 Cookie 无法防止 CSRF 攻击,而 Token 可以?
CSRF(Cross Site Request Forgery) 一般被翻译为 跨站请求伪造 。那么什么是 跨站请求伪造 呢?说简单点,就是用你的身份去发送一些对你不友好的请求。
一般使用 Cookie
来存储 SessionId
,当我们登陆后后端生成一个 SessionId
放在 Cookie 中返回给客户端,服务端通过 Redis 或者其他存储工具记录保存着这个 SessionId
,客户端登录以后每次请求都会带上这个 SessionId
,服务端通过这个 SessionId
来标示你这个人。如果别人通过 Cookie
拿到了 SessionId
后就可以代替你的身份访问系统了。
使用 Token
的话就不会存在这个问题,在我们登录成功获得 Token
之后,一般会选择存放在 localStorage
(浏览器本地存储)中。然后我们在前端通过某些方式会给每个发到后端的请求加上这个 Token
,这样就不会出现 CSRF 漏洞的问题。
JWT
JWT (JSON Web Token)是一种基于 Token 的认证授权机制。JWT 本身也是 Token,一种规范化之后的 JSON 结构的 Token。
JWT 由哪些部分组成?
- Header(头部) : 描述 JWT 的元数据,定义了生成签名的算法以及
Token
的类型。Header 被 Base64Url 编码后成为 JWT 的第一部分。 - Payload(载荷) : 用来存放实际需要传递的数据,包含声明(Claims),如
sub
(subject,主题)、jti
(JWT ID)。Payload 被 Base64Url 编码后成为 JWT 的第二部分。 - Signature(签名):服务器通过 Payload、Header 和一个密钥(Secret)使用 Header 里面指定的签名算法(默认是 HMAC SHA256)生成。生成的签名会成为 JWT 的第三部分。
Header
Header 通常由两部分组成:
typ
(Type):令牌类型,也就是 JWT。alg
(Algorithm):签名算法,比如 HS256。
{
"alg": "HS256",
"typ": "JWT"
}
JSON 形式的 Header 被转换成 Base64 编码,成为 JWT 的第一部分。
Payload
Payload 也是 JSON 格式数据,其中包含了 Claims(声明,包含 JWT 的相关信息)。
Claims 分为三种类型:
- Registered Claims(注册声明):预定义的一些声明,建议使用,但不是强制性的。
- Public Claims(公有声明):JWT 签发方可以自定义的声明,但是为了避免冲突,应该在 IANA JSON Web Token Registry 中定义它们。
- Private Claims(私有声明):JWT 签发方因为项目需要而自定义的声明,更符合实际项目场景使用。
常见声明:
iss
(issuer):JWT 签发方。iat
(issued at time):JWT 签发时间。sub
(subject):JWT 主题。aud
(audience):JWT 接收方。exp
(expiration time):JWT 的过期时间。nbf
(not before time):JWT 生效时间,早于该定义的时间的 JWT 不能被接受处理。jti
(JWT ID):JWT 唯一标识。
{
"uid": "ff1212f5-d8d1-4496-bf41-d2dda73de19a",
"sub": "1234567890",
"name": "John Doe",
"exp": 15323232,
"iat": 1516239022,
"scope": ["admin", "user"]
}
Payload 部分默认是不加密的,一定不要将隐私信息存放在 Payload 当中!!!
JSON 形式的 Payload 被转换成 Base64 编码,成为 JWT 的第二部分。
Signature
Signature 部分是对前两部分的签名,作用是防止 JWT(主要是 payload) 被篡改。 这个签名的生成需要用到:
- Header + Payload。
- 存放在服务端的密钥(一定不要泄露出去)。
- 签名算法。
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
算出签名以后,把 Header、Payload、Signature 三个部分拼成一个字符串,每个部分之间用"点"(.
)分隔,这个字符串就是 JWT 。
JWT 的生成过程
- 服务器生成 JWT 时,会按照以下步骤操作:
- 创建 Header 和 Payload:服务器根据用户信息生成
Header
和Payload
。 - 签名生成:使用 Header 中指定的算法(例如 HMAC SHA256),将
Header
和Payload
加密生成Signature
。 - 组合 JWT:将
Header
、Payload
和Signature
组合成完整的 JWT 字符串,发给客户端。
客户端携带 JWT 请求
客户端收到 JWT 后,会将其存储(通常在浏览器的 Local Storage 或 Cookie 中)。在每次请求时,客户端将 JWT 放在 HTTP 请求头的
Authorization
字段中发送给服务器.服务端校验 JWT 的过程
当服务器收到带有 JWT 的请求后,它不会直接信任这个 JWT,而是会按照以下步骤进行验证:
3.1 解析 JWT
服务器会将 JWT 拆解成三部分:
Header
、Payload
和Signature
,分别解码(因为它们是 base64 编码的)并提取出来。3.2 生成新的 Signature
服务器使用相同的算法和密钥(secret),对 JWT 中的
3.3 比较 Signature 服务器将 JWT 中的 `Signature` 与重新生成的 `newSignature` 进行比较:Header
和Payload
重新生成一个签名。生成的公式与之前相同:
- 如果两者一致:说明
Header
和Payload
没有被篡改,这个 JWT 是有效的。 - 如果两者不一致:说明
Header
或Payload
被修改过(可能是客户端恶意篡改),服务器会拒绝该请求,因为 JWT 的完整性无法保证。
如何基于 JWT 进行身份验证?
在基于 JWT 进行身份验证的的应用程序中,服务器通过 Payload、Header 和 Secret(密钥)创建 JWT 并将 JWT 发送给客户端。客户端接收到 JWT 之后,会将其保存在 Cookie 或者 localStorage 里面,以后客户端发出的所有请求都会携带这个令牌。
- 用户向服务器发送用户名、密码以及验证码用于登陆系统。
- 如果用户用户名、密码以及验证码校验正确的话,服务端会返回已经签名的 Token,也就是 JWT。
- 用户以后每次向后端发请求都在 Header 中带上这个 JWT 。
- 服务端检查 JWT 并从中获取用户相关信息。
如何防止 JWT 被篡改?
有了签名之后,即使 JWT 被泄露或者截获,黑客也没办法同时篡改 Signature、Header、Payload。
这是为什么呢?因为服务端拿到 JWT 之后,会解析出其中包含的 Header、Payload 以及 Signature 。服务端会根据 Header、Payload、密钥再次生成一个 Signature。拿新生成的 Signature 和 JWT 中的 Signature 作对比,如果一样就说明 Header 和 Payload 没有被修改。
不过,如果服务端的秘钥也被泄露的话,黑客就可以同时篡改 Signature、Header、Payload 了。黑客直接修改了 Header 和 Payload 之后,再重新生成一个 Signature 就可以了。
密钥一定保管好,一定不要泄露出去。JWT 安全的核心在于签名,签名安全的核心在密钥。
如何加强 JWT 的安全性?
- 使用安全系数高的加密算法。
- 使用成熟的开源库,没必要造轮子。
- JWT 存放在 localStorage 中而不是 Cookie 中,避免 CSRF 风险。
- 一定不要将隐私信息存放在 Payload 当中。
- 密钥一定保管好,一定不要泄露出去。JWT 安全的核心在于签名,签名安全的核心在密钥。
- Payload 要加入
exp
(JWT 的过期时间),永久有效的 JWT 不合理。并且,JWT 的过期时间不易过长。
JWT 的优势
- 无状态:
JWT 自身包含了身份验证所需要的所有信息,因此,我们的服务器不需要存储 Session 信息。这显然增加了系统的可用性和伸缩性,大大减轻了服务端的压力。
因此导致:不可控! 想要在 JWT 有效期内废弃一个 JWT 或者更改它的权限的话,并不会立即生效,通常需要等到有效期过后才可以。再比如说,当用户 Logout 的话,JWT 也还有效。 除非,我们在后端增加额外的处理逻辑比如将失效的 JWT 存储起来,后端先验证 JWT 是否有效再进行处理。 - 有效避免了 CSRF 攻击
- 适合移动端应用
- 单点登录友好
JWT 身份认证常见问题及解决办法
- 注销登录等场景下 JWT 还有效: > 1、将 JWT 存入数据库: 将有效的 JWT 存入数据库中,更建议使用内存数据库比如 Redis。如果需要让某个 JWT 失效就直接从 Redis 中删除这个 JWT 即可。但是,这样会导致每次使用 JWT 都要先从 Redis 中查询 JWT 是否存在的步骤,而且违背了 JWT 的无状态原则。 > 2、黑名单机制:和上面的方式类似,使用内存数据库比如 Redis 维护一个黑名单,如果想让某个 JWT 失效的话就直接将这个 JWT 加入到 黑名单 即可。然后,每次使用 JWT 进行请求的话都会先判断这个 JWT 是否存在于黑名单中。前两种方案的核心在于将有效的 JWT 存储起来或者将指定的 JWT 拉入黑名单。 > 3、修改密钥 (Secret) :为每个用户都创建一个专属密钥,如果我们想让某个 JWT 失效,我们直接修改对应用户的密钥即可。 > 4、保持令牌的有效期限短并经常轮换:很简单的一种方式。但是,会导致用户登录状态不会被持久记录,而且需要用户经常登录。
JWT 的续签问题
JWT 体积太大
- 尽量减少 JWT Payload(载荷)中的信息,只保留必要的用户和权限信息。
- 在传输 JWT 之前,使用压缩算法(如 GZIP)对 JWT 进行压缩以减少体积。
- 在某些情况下,使用传统的 Token 可能更合适。传统的 Token 通常只是一个唯一标识符,对应的信息(例如用户 ID、Token 过期时间、权限信息)存储在服务端,通常会通过 Redis 保存。
WebSocket
什么是 WebSocket?
WebSocket 是一种基于 TCP 连接的全双工通信协议,即客户端和服务器可以同时发送和接收数据。
WebSocket 不只能在基于浏览器的应用程序中使用,很多编程语言、框架和服务器都提供了 WebSocket 支持。
WebSocket 协议本质上是应用层的协议,用于弥补 HTTP 协议在持久通信能力上的不足。客户端和服务器仅需一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
WebSocket 和 HTTP 有什么区别?
都是基于 TCP 的应用层协议,都可以在网络中传输数据。
- WebSocket 是一种双向实时通信协议,而 HTTP 是一种单向通信协议。并且,HTTP 协议下的通信只能由客户端发起,服务器无法主动通知客户端。
- WebSocket 使用 ws:// 或 wss://(使用 SSL/TLS 加密后的协议,类似于 HTTP 和 HTTPS 的关系) 作为协议前缀,HTTP 使用 http:// 或 https:// 作为协议前缀。
- WebSocket 可以支持扩展,用户可以扩展协议,实现部分自定义的子协议,如支持压缩、加密等。
- WebSocket 通信数据格式比较轻量,用于协议控制的数据包头部相对较小,网络开销小,而 HTTP 通信每次都要携带完整的头部,网络开销较大(HTTP/2.0 使用二进制帧进行数据传输,还支持头部压缩,减少了网络开销)。
WebSocket 的工作过程是什么样的?
WebSocket 的工作过程可以分为以下几个步骤:
- 客户端向服务器发送一个 HTTP 请求,请求头中包含
Upgrade: websocket
和Sec-WebSocket-Key
等字段,表示要求升级协议为 WebSocket; - 服务器收到这个请求后,会进行升级协议的操作,如果支持 WebSocket,它将回复一个 HTTP 101 状态码,响应头中包含 ,
Connection: Upgrade
和Sec-WebSocket-Accept: xxx
等字段、表示成功升级到 WebSocket 协议。 - 客户端和服务器之间建立了一个 WebSocket 连接,可以进行双向的数据传输。数据以帧(frames)的形式进行传送,WebSocket 的每条消息可能会被切分成多个数据帧(最小单位)。发送端会将消息切割成多个帧发送给接收端,接收端接收消息帧,并将关联的帧重新组装成完整的消息。
- 客户端或服务器可以主动发送一个关闭帧,表示要断开连接。另一方收到后,也会回复一个关闭帧,然后双方关闭 TCP 连接。
另外,建立 WebSocket 连接之后,通过心跳机制来保持 WebSocket 连接的稳定性和活跃性。
SSE 与 WebSocket 有什么区别?
TCP 与 UDP
TCP 与 UDP 的区别
- 是否面向连接:UDP 在传送数据之前不需要先建立连接。而 TCP 提供面向连接的服务,在传送数据之前必须先建立连接,数据传送结束后要释放连接。
- 是否是可靠传输:远地主机在收到 UDP 报文后,不需要给出任何确认,并且不保证数据不丢失,不保证是否顺序到达。TCP 提供可靠的传输服务,TCP 在传递数据之前,会有三次握手来建立连接,而且在数据传递时,有确认、窗口、重传、拥塞控制机制。通过 TCP 连接传输的数据,无差错、不丢失、不重复、并且按序到达。
- 是否有状态:这个和上面的“是否可靠传输”相对应。TCP 传输是有状态的,这个有状态说的是 TCP 会去记录自己发送消息的状态比如消息是否发送了、是否被接收了等等。为此 ,TCP 需要维持复杂的连接状态表。而 UDP 是无状态服务,简单来说就是不管发出去之后的事情了。
- 传输效率:由于使用 TCP 进行传输的时候多了连接、确认、重传等机制,所以 TCP 的传输效率要比 UDP 低很多。
- 传输形式:TCP 是面向字节流的,UDP 是面向报文的。
- 首部开销:TCP 首部开销(20 ~ 60 字节)比 UDP 首部开销(8 字节)要大。
- 是否提供广播或多播服务:TCP 只支持点对点通信,UDP 支持一对一、一对多、多对一、多对多;
什么时候选择 TCP,什么时候选 UDP?
- UDP 一般用于即时通信,比如:语音、 视频、直播等等。这些场景对传输数据的准确性要求不是特别高,比如你看视频即使少个一两帧,实际给人的感觉区别也不大。
- TCP 用于对传输准确性要求特别高的场景,比如文件传输、发送和接收邮件、远程登录等等。
HTTP 基于 TCP 还是 UDP?
HTTP/3.0 之前是基于 TCP 协议的,而 HTTP/3.0 将弃用 TCP,改用 基于 UDP 的 QUIC 协议
解决了 HTTP/2 中存在的队头阻塞问题。队头阻塞是指在 HTTP/2.0 中,多个 HTTP 请求和响应共享一个 TCP 连接,如果其中一个请求或响应因为网络拥塞或丢包而被阻塞,那么后续的请求或响应也无法发送,导致整个连接的效率降低。这是由于 HTTP/2.0 在单个 TCP 连接上使用了多路复用,受到 TCP 拥塞控制的影响,少量的丢包就可能导致整个 TCP 连接上的所有流被阻塞。HTTP/3.0 在一定程度上解决了队头阻塞问题,一个连接建立多个不同的数据流,这些数据流之间独立互不影响,某个数据流发生丢包了,其数据流不受影响(本质上是多路复用+轮询)。
除了解决队头阻塞问题,HTTP/3.0 还可以减少握手过程的延迟。在 HTTP/2.0 中,如果要建立一个安全的 HTTPS 连接,需要经过 TCP 三次握手和 TLS 握手:
- TCP 三次握手:客户端和服务器交换 SYN 和 ACK 包,建立一个 TCP 连接。这个过程需要 1.5 个 RTT(round-trip time),即一个数据包从发送到接收的时间。
- TLS 握手:客户端和服务器交换密钥和证书,建立一个 TLS 加密层。这个过程需要至少 1 个 RTT(TLS 1.3)或者 2 个 RTT(TLS 1.2)。
所以,HTTP/2.0 的连接建立就至少需要 2.5 个 RTT(TLS 1.3)或者 3.5 个 RTT(TLS 1.2)。而在 HTTP/3.0 中,使用的 QUIC 协议(TLS 1.3,TLS 1.3 除了支持 1 个 RTT 的握手,还支持 0 个 RTT 的握手)连接建立仅需 0-RTT 或者 1-RTT。这意味着 QUIC 在最佳情况下不需要任何的额外往返时间就可以建立新连接。
使用 TCP 的协议有哪些?使用 UDP 的协议有哪些?
TCP 三次握手和四次挥手(非常重要)
- 第一次握手:客户端发送 SYN
- 客户端向服务器发送一个 SYN 报文段(同步序列号),表示请求建立连接。
- SYN 报文段中包含了一个初始序列号
Seq = x
,表示客户端通信的序列号起始点。 - 在发送 SYN 报文段后,客户端进入
SYN-SENT
状态,等待服务器的响应。
- 第二次握手:服务器发送 SYN + ACK
- 服务器收到客户端的 SYN 报文段后,确认自己收到了连接请求,并且也准备好进行连接。
- 服务器向客户端发送一个 SYN 报文段,同时包含一个 ACK 报文段,用于确认收到客户端的 SYN 请求。这个报文段称为 SYN + ACK 报文段。
- SYN 部分:服务器也发送自己的初始序列号
Seq = y
,表示服务器通信的序列号起始点。 - ACK 部分:将客户端的序列号
x + 1
放入 ACK 字段中,表示确认接收了客户端的 SYN 报文。
- SYN 部分:服务器也发送自己的初始序列号
- 在发送完 SYN + ACK 报文段后,服务器进入
SYN-RECEIVED
状态,等待客户端的确认。
- 第三次握手:客户端发送 ACK
- 客户端收到服务器的 SYN + ACK 报文段后,确认服务器也准备好了连接。
- 客户端向服务器发送一个 ACK 报文段,确认接收到服务器的 SYN。
- 在 ACK 报文段中,客户端将服务器的序列号
y + 1
放入 ACK 字段,表示确认接收到服务器的 SYN。 - 此时客户端的序列号为
Seq = x + 1
(初始序列号基础上加1,后续数据传输从此序列号开始)。
- 在 ACK 报文段中,客户端将服务器的序列号
客户端发送完 ACK 报文段后,进入
ESTABLISHED
状态,表示连接已建立,准备传输数据。最终状态
- 服务器收到客户端的 ACK 报文段后,也进入
ESTABLISHED
状态。 - 此时,TCP 连接成功建立,客户端和服务器可以开始数据传输。
为什么要三次握手?
三次握手的目的是建立可靠的通信信道,说到通讯,简单来说就是数据的发送与接收,而三次握手最主要的目的就是双方确认自己与对方的发送与接收是正常的。
- 第一次握手:Client 什么都不能确认;Server 确认了对方发送正常,自己接收正常
- 第二次握手:Client 确认了:自己发送、接收正常,对方发送、接收正常;Server 确认了:对方发送正常,自己接收正常
- 第三次握手:Client 确认了:自己发送、接收正常,对方发送、接收正常;Server 确认了:自己发送、接收正常,对方发送、接收正常
第 2 次握手传回了 ACK,为什么还要传回 SYN?
三次握手过程中可以携带数据吗?
断开连接-TCP 四次挥手
- 第一次挥手:客户端发送一个 FIN(SEQ=x) 标志的数据包->服务端,用来关闭客户端到服务端的数据传送。然后客户端进入 FIN-WAIT-1 状态。
- 第二次挥手:服务端收到这个 FIN(SEQ=X) 标志的数据包,它发送一个 ACK (ACK=x+1)标志的数据包->客户端 。然后服务端进入 CLOSE-WAIT 状态,客户端进入 FIN-WAIT-2 状态。
- 第三次挥手:服务端发送一个 FIN (SEQ=y)标志的数据包->客户端,请求关闭连接,然后服务端进入 LAST-ACK 状态。
- 第四次挥手:客户端发送 ACK (ACK=y+1)标志的数据包->服务端,然后客户端进入TIME-WAIT状态,服务端在收到 ACK (ACK=y+1)标志的数据包后进入 CLOSE 状态。此时如果客户端等待 2MSL 后依然没有收到回复,就证明服务端已正常关闭,随后客户端也可以关闭连接了。
为什么要四次挥手?
TCP 是全双工通信,可以双向传输数据。任何一方都可以在数据传送结束后发出连接释放的通知,待对方确认后进入半关闭状态。当另一方也没有数据再发送的时候,则发出连接释放通知,对方确认后就完全关闭了 TCP 连接。
TCP 如何保证传输的可靠性?(重要)
- 基于数据块传输:应用数据被分割成 TCP 认为最适合发送的数据块,再传输给网络层,数据块被称为报文段或段。
- 对失序数据包重新排序以及去重:TCP 为了保证不发生丢包,就给每个包一个序列号,有了序列号能够将接收到的数据根据序列号排序,并且去掉重复序列号的数据就可以实现数据包去重。
- 校验和 : TCP 将保持它首部和数据的检验和。这是一个端到端的检验和,目的是检测数据在传输过程中的任何变化。如果收到段的检验和有差错,TCP 将丢弃这个报文段和不确认收到此报文段。
- 重传机制 : 在数据包丢失或延迟的情况下,重新发送数据包,直到收到对方的确认应答(ACK)。TCP 重传机制主要有:基于计时器的重传(也就是超时重传)、快速重传(基于接收端的反馈信息来引发重传)、SACK(在快速重传的基础上,返回最近收到的报文段的序列号范围,这样客户端就知道,哪些数据包已经到达服务器了)、D-SACK(重复 SACK,在 SACK 的基础上,额外携带信息,告知发送方有哪些数据包自己重复接收了)。关于重传机制的详细介绍,可以查看详解 TCP 超时与重传机制这篇文章。
- 流量控制 : TCP 连接的每一方都有固定大小的缓冲空间,TCP 的接收端只允许发送端发送接收端缓冲区能接纳的数据。当接收方来不及处理发送方的数据,能提示发送方降低发送的速率,防止包丢失。TCP 使用的流量控制协议是可变大小的滑动窗口协议(TCP 利用滑动窗口实现流量控制)。
- 拥塞控制 : 当网络拥塞时,减少数据的发送。TCP 在发送数据的时候,需要考虑两个因素:一是接收方的接收能力,二是网络的拥塞程度。接收方的接收能力由滑动窗口表示,表示接收方还有多少缓冲区可以用来接收数据。网络的拥塞程度由拥塞窗口表示,它是发送方根据网络状况自己维护的一个值,表示发送方认为可以在网络中传输的数据量。发送方发送数据的大小是滑动窗口和拥塞窗口的最小值,这样可以保证发送方既不会超过接收方的接收能力,也不会造成网络的过度拥塞。
IP
IP 协议的作用是什么?
属于网络层的协议,主要作用是定义数据包的格式、对数据包进行路由和寻址,以便它们可以跨网络传播并到达正确的目的地。
IP 寻址如何工作?
当网络设备发送 IP 数据包时,数据包中包含了 源 IP 地址 和 目的 IP 地址 。源 IP 地址用于标识数据包的发送方设备或域,而目的 IP 地址则用于标识数据包的接收方设备或域。这类似于一封邮件中同时包含了目的地地址和回邮地址。
网络设备根据目的 IP 地址来判断数据包的目的地,并将数据包转发到正确的目的地网络或子网络,从而实现了设备间的通信。
IPv4 和 IPv6 有什么区别?
如何获取客户端真实 IP?
NAT 的作用是什么?
NAT(Network Address Translation,网络地址转换) 主要用于在不同网络之间转换 IP 地址。它允许将私有 IP 地址(如在局域网中使用的 IP 地址)映射为公有 IP 地址(在互联网中使用的 IP 地址)或者反向映射,从而实现局域网内的多个设备通过单一公有 IP 地址访问互联网。
NAT 不光可以缓解 IPv4 地址资源短缺的问题,还可以隐藏内部网络的实际拓扑结构,使得外部网络无法直接访问内部网络中的设备,从而提高了内部网络的安全性。
ARP
什么是 Mac 地址?
MAC 地址的全称是 媒体访问控制地址(Media Access Control Address)。如果说,互联网中每一个资源都由 IP 地址唯一标识(IP 协议内容),那么一切网络设备都由 MAC 地址唯一标识。
ARP 协议解决了什么问题?
ARP 协议,全称 地址解析协议(Address Resolution Protocol),它解决的是网络层地址和链路层地址之间的转换问题。因为一个 IP 数据报在物理上传输的过程中,总是需要知道下一跳(物理上的下一个目的地)该去往何处,但 IP 地址属于逻辑地址,而 MAC 地址才是物理地址,ARP 协议解决了 IP 地址转 MAC 地址的一些问题。