计算机网络基础
CDN
CDN 内容分发网络(Content Delivery Network),是一种通过位于全球各地的多个服务器来分发内容的网络服务。CDN 的目的是提高网站的访问速度、减少网络延迟,以及增加网站的稳定性和安全性。 原理: 目前互联网应用中都包含了大量的静态内容,如果不做任何处理,所有的请求都指向源站服务器的话,不仅会消耗大量的带宽,还会拖累页面的加载速度,影响用户的体验。 CDN的出现可以解决上述问题。CDN的本质仍然是一个缓存,通过在现有网络中增加一个新的缓存节点,可以将数据缓存在离用户最近的地方,使用户以最快的速度获取数据,不需要每个用户的请求都去源站上去获取,避免了网络拥挤,缓解源站压力。 当用户访问域名时,会先访问离他最近的CDN服务器,如果该服务器没有缓存,就会向域名原ip地址或者更上层的父级服务器进行查询,直到获取到数据,获取到数据后会在该CDN服务器上缓存,下次该地区的用户再次访问该CDN服务器时,就能直接获取到缓存,而不用去访问源ip地址。
WebSocket
- WebSocket 是一种在单个 TCP 连接上进行全双工通信的网络传输协议。
- WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。客户端和服务器只需要完成一次握手,两者之间就可以创建持久性的连接,并进行双向数据传输。
功能和特性:
- 实时通信:WebSocket 支持双向通信,浏览器和服务器可以实时地发送消息和接收消息,无需频繁地发起请求。
- 低延迟:由于 WebSocket 是基于单个 TCP 连接的,不需要在每个请求之间建立和关闭连接,可以减少网络延迟和建立连接的开销,实现更快的实时通信。
- 跨域支持:WebSocket 支持跨域通信,允许不同域的客户端与服务器建立连接,实现跨域数据传输。
- 高效的数据传输:WebSocket 使用二进制协议,可以更高效地传输数据和处理大量的数据传输,适用于实时游戏、聊天应用等需要频繁数据交互的场景。
- 自定义的消息格式:WebSocket 允许自定义消息格式和消息处理逻辑,可以根据业务需求设计消息结构和处理机制。
适用场景
- 实时聊天应用: WebSocket 是实现实时聊天室、即时通讯应用的理想选择,因为它能够提供低延迟和高实时性。
- 在线协作和协同编辑: 对于需要多用户协同工作的应用,如协同编辑文档或绘图,WebSocket 的实时性使得用户能够看到其他用户的操作。
- 实时数据展示:对于需要实时展示数据变化的应用,例如股票行情、实时监控系统等,WebSocket 提供了一种高效的通信方式。
- 在线游戏:在线游戏通常需要快速、实时的通信,WebSocket 能够提供低延迟和高并发的通信能力。
- 推送服务:用于实现消息推送服务,向客户端主动推送更新或通知。
应用层的协议:
- HTTP:用于在网络上传输超文本文档,是 Web 上最常见的应用层协议,用于客户端和服务器之间的通信。
- HTTPS:是 HTTP 的安全版本,使用 SSL/TLS 协议对数据进行加密和身份验证,用于保护 Web 通信的安全性。
- DNS:用于将域名解析为 IP 地址的协议,使用户能够通过易记的域名访问互联网资源。
- WebSocket
传输层协议:
- TCP:TCP是一种面向连接的、可靠的传输协议,它通过数据包的序列号、确认和重传机制来确保数据的可靠传输。TCP 还负责流量控制和拥塞控制,确保网络中的数据传输稳定顺畅。
- UDP: UDP是一种无连接的传输协议,它提供了数据包的简单传输服务,但不保证数据的可靠性和顺序性。具有传输速度快,开销低的优点。UDP 适用于对实时性要求较高、对数据丢失较为容忍的应用场景,如音频、视频传输等。
Cookie,Session,Token,JWT
- Cookie:
- cookie存储在客户端,cookie是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器下次向同一服务器再发送请求时被携带并发送到服务器上,以便服务器识别用户的身份并追踪用户的访问记录
- cookie是不可跨域的,每个cookie会绑定单一的域名,无法在别的域名下获取使用。一级域名和二级域名之间是允许共享使用的(靠的是domain)
- cookie主要用于身份认证,会话管理(如登录状态,购物车内容),个性化设置,数据分析
- Session:
- session是另外一种记录服务端和客户端会话状态的机制
- session是基于cookie实现的,session存储在服务器端,sessionId会被存储到客户端的cookie中
- Token:
- Token 是一种用于身份验证的字符串凭证,通常由服务器生成,发送给客户端,并由客户端在后续请求中携带。 另一种token——refresh token:refresh token是专用于刷新access token 的token。客户端直接用它去更新access token,无需用户进行额外的操作
- JWT JWT(JSON Web Tokens):是目前最流行的跨域认证解决方案,是一种认证授权机制 认证流程:
- 用户输入用户名密码服务端认证成功后,会返回给客户端一个JWT
- 客户端将token保存到本地
- 当用户访问一个受保护的资源或者路由时,需要请求头的Authorization字段中使用Bearer模式添加JWT
- 服务端的保护路由会检查请求头中的JWT信息,如果合法,则允许用户的行为 JWT和Token的区别 相同:
- 都是访问资源的令牌
- 都可以记录用户的信息
- 都可以轻松地在不同服务之间传递,并且无需在服务器端保存状态信息。
- 都是只有验证成功后,客户端才能访问服务端上受保护的资源 区别:
- Token:服务端验证客户端发送过来的token时,需要查询数据库获取用户信息然后来验证token是否有效
- JWT:将Token和payload加密后存储于客户端,服务端只需要使用密钥解密进行校验(校验也是JWT自己实现的)即可,不需要查询或者减少查询数据库,因为JWT自包含了用户信息和加密的数据
token过期了如何续期
- 强制重新登录
- 自动刷新token
- 前端携带旧的token请求刷新
- 使用锁机制
- 提前提醒用户
如何优化每次都需要token的情况
- Token缓存
- Token续签
- Refresh Token
- Token自动刷新
- 优化网络请求
服务端推送的方法有哪些?
- WebSocket:WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议,可以实现服务器和客户端之间的实时双向通信。服务器可以主动向客户端发送消息,而且客户端也可以向服务器发送消息。
- Server-Sent Events(SSE)
- Long Polling:长轮询是一种模拟服务器推送的技术,客户端定时向服务器发送请求,服务器在有新数据时才返回相应,客户端再立即发送下一个请求。这种方式不同于传统的短轮询,通过不断发送请求,实现了服务器向客户端的推送效果。
SSE流式传输
SSE 全称为 Server-sent events , 是一种基于 HTTP 协议的通信技术,允许服务器主动向客户端(通常是Web浏览器)发送更新。 它是 HTML5 标准的一部分,设计初衷是用来建立一个单向的服务器到客户端连接,使得服务器可以实时地向客户端发送数据。这种服务端实时向客户端发送数据的传输方式,其实就是流式传输。
流式传输的好处
在 SSE 技术出现之前,我们习惯把需要等待服务端返回的过程称为长轮询。长轮询最大的弊端是当服务端响应请求之前,客户端发送的所有请求都不会被受理。并且服务端发送响应的前提是客户端发起请求。前后端通信过程中,我们常采用 ajax 、axios 来异步获取结果,这个过程,其实也是长轮询的过程。
而同为采用 http 协议通信方式的 SSE 流式传输,相比于长轮询模式来说,优势在于可以在不需要客户端介入的情况下,多次向客户端发送响应,直至客户端关闭连接。这对于需要服务端实时推送内容至客户端的场景可方便太多了!
SSE技术原理
- 参数设置: SSE 本质是一个基于 http 协议的通信技术。因此想要使用 SSE 技术构建需要服务器实时推送信息到客户端的连接,只需要将传统的 http 响应头的 contentType 设置为 text/event-stream 。并且为了保证客户端展示的是最新数据,需要将 Cache-Control 设置为 no-cache 。在此基础上,SSE 本质是一个 TCP 连接,因此为了保证 SSE 的持续开启,需要将 Connection 设置为 keep-alive 。s
Content-Type: text/event-stream Cache-Control: no-cache Connection: keep-alive
规范:
- 服务端基本响应格式 SSE 响应主要由一系列以两个换行符分隔的事件组成。每个事件可以包含以下字段:s字段之间用单个换行符分隔,而事件之间用两个换行符分隔。
data:事件的数据。如果数据跨越多行,每行都应该以data:开始。 id:事件的唯一标识符。客户端可以使用这个ID来恢复事件流。 event:自定义事件类型。客户端可以根据不同的事件类型来执行不同的操作。 retry:建议的重新连接时间(毫秒)。如果连接中断,客户端将等待这段时间后尝试重新连接。
- 客户端处理格式 客户端使用 EventSource 接口监听 SSE 消息:js
const evtSource = new EventSource('path/to/sse'); evtSource.onmessage = function(event) { console.log(event.data); // 处理收到的数据 }
SSE应用场景
SSE 作为基于 http 协议由服务端向客户端单向推送消息的通信技术,对于需要服务端主动推送消息的场景来说,是非常适合的:
- 倒计时同步
- 实时天气
- 实时库存更新
- 实时股票
- 秒杀状态通知
SSE与WebSocket对比
SSE 与 WebSocket 各有优缺点,对于需要客户端与服务端高频交互的场景,WebSocket 确实更适合;但对于只需要服务端单向数据传输的场景,SSE 确实能耗更低,且不需要客户端感知。
网络安全
XSS攻击
Cross-Site Scripting(跨站脚本攻击)简称 XSS,是一种代码注入攻击。攻击者通过在目标网站上注入恶意脚本,使之在用户的浏览器上运行。利用这些恶意脚本,攻击者可获取用户的敏感信息如 Cookie、SessionID 等,进而危害数据安全。 XSS 的本质是:恶意代码未经过滤,与网站正常的代码混在一起;浏览器无法分辨哪些脚本是可信的,导致恶意脚本被执行。 而由于直接在用户的终端执行,恶意代码能够直接获取用户的信息,或者利用这些信息冒充用户向网站发起攻击者定义的请求。 在部分情况下,由于输入的限制,注入的恶意脚本比较短。但可以通过引入外部的脚本,并由浏览器执行,来完成比较复杂的攻击策略。
用户是通过哪种方法“注入”恶意脚本的呢? 不仅仅是业务上的“用户的 UGC 内容”可以进行注入,包括 URL 上的参数等都可以是攻击的来源。在处理输入时,以下内容都不可信:
- 来自用户的 UGC 信息
- 来自第三方的链接
- URL 参数
- POST 参数
- Referer (可能来自不可信的来源)
- Cookie (可能来自其他子域注入)
XSS分类
- 存储型XSS 攻击步骤:
- 攻击者将恶意代码提交到目标网站的数据库中。
- 用户打开目标网站时,网站服务端将恶意代码从数据库取出,拼接在 HTML 中返回给浏览器。
- 用户浏览器接收到响应后解析执行,混在其中的恶意代码也被执行。
- 恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户的行为,调用目标网站接口执行攻击者指定的操作。
这种攻击常见于带有用户保存数据的网站功能,如论坛发帖、商品评论、用户私信等。
- 反射型XSS 攻击步骤:
- 攻击者构造出特殊的 URL,其中包含恶意代码。
- 用户打开带有恶意代码的 URL 时,网站服务端将恶意代码从 URL 中取出,拼接在 HTML 中返回给浏览器。
- 用户浏览器接收到响应后解析执行,混在其中的恶意代码也被执行。
- 恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户的行为,调用目标网站接口执行攻击者指定的操作。
反射型 XSS 跟存储型 XSS 的区别是:存储型 XSS 的恶意代码存在数据库里,反射型 XSS 的恶意代码存在 URL 里。 反射型 XSS 漏洞常见于通过 URL 传递参数的功能,如网站搜索、跳转等。 由于需要用户主动打开恶意的 URL 才能生效,攻击者往往会结合多种手段诱导用户点击。 POST 的内容也可以触发反射型 XSS,只不过其触发条件比较苛刻(需要构造表单提交页面,并引导用户点击),所以非常少见。
- DOM型XSS 攻击步骤:
- 攻击者构造出特殊的 URL,其中包含恶意代码。
- 用户打开带有恶意代码的 URL。
- 用户浏览器接收到响应后解析执行,前端 JavaScript 取出 URL 中的恶意代码并执行。
- 恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户的行为,调用目标网站接口执行攻击者指定的操作。
DOM 型 XSS 跟前两种 XSS 的区别:DOM 型 XSS 攻击中,取出和执行恶意代码由浏览器端完成,属于前端 JavaScript 自身的安全漏洞,而其他两种 XSS 都属于服务端的安全漏洞。
XSS攻击的预防
CSRF攻击
CSRF(Cross-site request forgery)跨站请求伪造:攻击者诱导受害者进入第三方网站,在第三方网站中,向被攻击网站发送跨站请求。利用受害者在被攻击网站已经获取的注册凭证,绕过后台的用户验证,达到冒充用户对被攻击的网站执行某项操作的目的。
一个典型的CSRF攻击有着如下的流程:
- 受害者登录a.com,并保留了登录凭证(Cookie)。
- 攻击者引诱受害者访问了b.com。
- b.com 向 a.com 发送了一个请求:a.com/act=xx。浏览器会…
- a.com接收到请求后,对请求进行验证,并确认是受害者的凭证,误以为是受害者自己发送的请求。
- a.com以受害者的名义执行了act=xx。
- 攻击完成,攻击者在受害者不知情的情况下,冒充受害者,让a.com执行了自己定义的操作。
几种常见的攻击类型
- GET类型的CSRF
- POST类型的CSRF
- 链接类型的CSRF
CSRF的特点
- 攻击一般发起在第三方网站,而不是被攻击的网站。被攻击的网站无法防止攻击发生。
- 攻击利用受害者在被攻击网站的登录凭证,冒充受害者提交操作;而不是直接窃取数据。
- 整个过程攻击者并不能获取到受害者的登录凭证,仅仅是“冒用”。
- 跨站请求可以用各种方式:图片URL、超链接、CORS、Form提交等等。部分请求方式可以直接嵌入在第三方论坛、文章中,难以进行追踪。
CSRF通常是跨域的,因为外域通常更容易被攻击者掌控。但是如果本域下有容易被利用的功能,比如可以发图和链接的论坛和评论区,攻击可以直接在本域下进行,而且这种攻击更加危险。
防护策略
针对CSRF的两个特点:
- CSRF(通常)发生在第三方域名。
- CSRF攻击者不能获取到Cookie等信息,只是使用。
防护策略
- 阻止不明外域的访问
- 同源检测:阻止检测外域请求
- Samesite Cookie属性:为了从源头上解决这个问题,Google起草了一份草案来改进HTTP协议,那就是为Set-Cookie响应头新增Samesite属性,它用来标明这个 Cookie是个“同站 Cookie”,同站Cookie只能作为第一方Cookie,不能作为第三方Cookie,Samesite 有两个属性值,分别是 Strict 和 Lax(严格和宽松模式)
- 提交时要求附加本域才能获取的信息
- CSRF Token:要求所有的用户请求都携带一个CSRF攻击者无法获取到的Token
- 分布式校验:Token通常是使用UserID、时间戳和随机数,通过加密的方法生成。在token解密成功之后,服务器可以访问解析值,Token中包含的UserID和时间戳将会被拿来被验证有效性,将UserID与当前登录的UserID进行比较,并将时间戳与当前时间进行比较。
- 双重Cookie验证:使用双重提交Cookie。利用CSRF攻击不能获取到用户Cookie的特点,我们可以要求Ajax和表单请求携带一个Cookie中的值。
防止网站被利用
对于来自黑客自己的网站,我们无法防护。但对其他情况,那么如何防止自己的网站被利用成为攻击的源头呢?
- 严格管理所有的上传接口,防止任何预期之外的上传内容(例如HTML)。
- 添加Header X-Content-Type-Options: nosniff 防止黑客上传HTML内容的资源(例如图片)被解析为网页。
- 对于用户上传的图片,进行转存或者校验。不要直接使用用户填写的图片链接。
- 当前用户打开其他用户填写的链接时,需告知风险(这也是很多论坛不允许直接在内容中发布外域链接的原因之一,不仅仅是为了用户留存,也有安全考虑)。