You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
WebSocket和HTTP都是应用层协议,都基于 TCP 协议。但是 WebSocket 是一种双向通信协议,在建立连接之后,WebSocket 的 server 与 client 都能主动向对方发送或接收数据。同时,WebSocket 在建立连接时需要借助 HTTP 协议,连接建立好了之后 client 与 server 之间的双向通信就与 HTTP 无关了。
我们先来看个例子👇
本地文件socket.html向localhost:3000发生数据和接受数据👇
// socket.html<script>
let socket = new WebSocket('ws://localhost:3000');
socket.onopen = function () {socket.send('我爱你');//向服务器发送数据}
socket.onmessage = function (e) {console.log(e.data);//接收服务器返回的数据}</script>
后端部分👇
// server.js
let WebSocket = require('ws'); //记得安装ws
let wss = new WebSocket.Server({port:3000});
wss.on('connection',function(ws) {
ws.on('message', function (data) {
console.log(data);
ws.send('我不爱你')
});
})
如果 你想去尝试的话,建议可以去玩一玩Socket.io,
这是因为原生WebSocket API使用起来不太方便,它很好地封装了webSocket接口
提供了更简单、灵活的接口,也对不支持webSocket的浏览器提供了向下兼容。
nginx代理跨域
17. 谈一谈你对XSS攻击理解
什么是 XSS 攻击
XSS 全称是 Cross Site Scripting ,为了与CSS区分开来,故简称 XSS,翻译过来就是“跨站脚本”。
XSS是指黑客往 HTML 文件中或者 DOM 中注入恶意脚本,从而在用户浏览页面时利用注入的恶意脚本对用户实施攻击的一种手段。
前言
想要成为一名合格的前端工程师,掌握相关浏览器的工作原理是必备的,这样子才会有一个完整知识体系,要是「能参透浏览器的工作原理,你就能解决80%的前端难题」。
这篇梳理的话,更多的是对浏览器工作原理篇的查缺补漏,对于一些没有涉及到的知识点,准备梳理梳理,也正好回顾之前梳理的内容。
感谢掘友的鼓励与支持🌹🌹🌹,往期文章都在最后梳理出来了(●'◡'●)
接下来以问题形式展开梳理
1. 常见的浏览器内核有哪些?
2. 浏览器的主要组成部分是什么?
值得注意的是,和大多数浏览器不同,Chrome 浏览器的每个标签页都分别对应一个呈现引擎实例。每个标签页都是一个独立的进程。
2. 浏览器的主要组成部分是什么?
值得注意的是,和大多数浏览器不同,Chrome 浏览器的每个标签页都分别对应一个呈现引擎实例。每个标签页都是一个独立的进程。
3. 为什么JavaScript是单线程的,与异步冲突吗
补充:JS中其实是没有线程概念的,所谓的单线程也只是相对于多线程而言。JS的设计初衷就没有考虑这些,针对JS这种不具备并行任务处理的特性,我们称之为“单线程”。
JS的单线程是指一个浏览器进程中只有一个JS的执行线程,同一时刻内只会有一段代码在执行。
举个通俗例子,假设JS支持多线程操作的话,JS可以操作DOM,那么一个线程在删除DOM,另外一个线程就在获取DOM数据,这样子明显不合理,这算是证明之一。
来看段代码👇
打印结果就是首先是很多个first,然后再是second。
异步机制是浏览器的两个或以上常驻线程共同完成的,举个例子,比如异步请求由两个常驻线程,JS执行线程和事件触发线程共同完成的。
再比如定时器触发(settimeout和setinterval) 是由浏览器的定时器线程执行的定时计数,然后在定时时间把定时处理函数的执行请求插入到JS执行队列的尾端(所以用这两个函数的时候,实际的执行时间是大于或等于指定时间的,不保证能准确定时的)。
所以这么说,JS单线程与异步更多是浏览器行为,之间不冲突。
4. CSS加载会造成阻塞吗
先给出结论
CSS
不会阻塞DOM
解析,但会阻塞DOM
渲染。CSS
会阻塞JS执行,并不会阻塞JS文件下载先讲一讲CSSOM作用
由之前讲过的浏览器渲染流程我们可以看出:
DOM 和 CSSOM通常是并行构建的,所以CSS 加载不会阻塞 DOM 的解析。
然而由于Render Tree 是依赖DOM Tree和 CSSOM Tree的,所以它必须等到两者都加载完毕后,完成相应的构建,才开始渲染,因此,CSS加载会阻塞DOM渲染。
由于 JavaScript 是可操纵 DOM 和 css 样式 的,如果在修改这些元素属性同时渲染界面(即 JavaScript 线程和 UI 线程同时运行),那么渲染线程前后获得的元素数据就可能不一致了。
因此为了防止渲染出现不可预期的结果,浏览器设置 GUI 渲染线程与 JavaScript 引擎为互斥的关系。
有个需要注意的点就是:
有时候JS需要等到CSS的下载,这是为什么呢?
仔细思考一下,其实这样做是有道理的,如果脚本的内容是获取元素的样式,宽高等
CSS
控制的属性,浏览器是需要计算的,也就是依赖于CSS
。浏览器也无法感知脚本内容到底是什么,为避免样式获取,因而只好等前面所有的样式下载完后,再执行JS
。JS文件下载和CSS文件下载是并行的,有时候CSS文件很大,所以JS需要等待。
因此,样式表会在后面的 js 执行前先加载执行完毕,所以css 会阻塞后面 js 的执行。
5. 为什么JS会阻塞页面加载
先给出结论👇
这也是为什么说JS文件放在最下面的原因,那为什么会阻塞DOM解析呢
你可以这样子理解:
另外,如果 JavaScript 文件中没有操作 DOM 相关代码,就可以将该 JavaScript 脚本设置为异步加载,通过 async 或 defer 来标记代码
6. defer 和 async 的区别 ?
DOMContentLoaded
事件前执行,如果缺少src
属性(即内嵌脚本),该属性不应被使用,因为这种情况下它不起作用7. DOMContentLoaded 与 load 的区别 ?
那么也就是先DOMContentLoaded -> load,那么在Jquery中,使用$(document).read(callback)监听的就是DOMContentLoaded事件,$(document).load(callback)监听的就是load事件。
那我们可以聊一聊它们与async和defer区别
8. 为什么CSS动画比JavaScript高效
我觉得这个题目说法上可能就是行不通,不能这么说,如果了解的话,都知道will-change只是一个优化的手段,使用JS改变transform也可以享受这个属性带来的变化,所以这个说法上有点不妥。
所以围绕这个问题展开话,更应该说建议推荐使用CSS动画,至于为什么呢,涉及的知识点大概就是重排重绘,合成,这方面的点,我在浏览器渲染流程中也提及了。
尽可能的避免重排和重绘,具体是哪些操作呢,如果非要去操作JS实现动画的话,有哪些优化的手段呢?
比如👇
createDocumentFragment
进行批量的 DOM 操作剩下的东西就留给你们思考吧,希望我这是抛砖引玉吧(●'◡'●)
9. 能不能实现事件防抖和节流
函数节流(throttle)
抓取一个关键的点:就是执行的时机。要做到控制执行的时机,我们可以通过一个开关,与定时器setTimeout结合完成。
函数防抖(debounce)
核心思想:每次事件触发都会删除原有定时器,建立新的定时器。通俗意思就是反复触发函数,只认最后一次,从最后一次开始计时。
代码:
如何使用 debounce 和 throttle 以及常见的坑
自己造一个 debounce / throttle 的轮子看起来多么诱人,或者随便找个博文复制过来。我是建议直接使用 underscore 或 Lodash 。如果仅需要
_.debounce
和_.throttle
方法,可以使用 Lodash 的自定义构建工具,生成一个 2KB 的压缩库。使用以下的简单命令即可:常见的坑是,不止一次地调用
_.debounce
方法:debounce 方法保存到一个变量以后,就可以用它的私有方法
debounced_version.cancel()
,lodash 和 underscore.js 都有效。适合应用场景
防抖
节流
10. 谈一谈你对requestAnimationFrame(rAF)理解
正好跟节流有点关系,有点相似处,就准备梳理一下这个知识点。
高性能动画是什么,那它衡量的标准是什么呢?
动画帧率可以作为衡量标准,一般来说画面在 60fps 的帧率下效果比较好。
换算一下就是,每一帧要在 16.7ms (16.7 = 1000/60) 内完成渲染。
我们来看看MDN对它的解释吧👇
当我们调用这个函数的时候,我们告诉它需要做两件事:
rAF与 setTimeout 相比
rAF(requestAnimationFrame) 最大的优势是由系统来决定回调函数的执行时机。
具体一点讲就是,系统每次绘制之前会主动调用 rAF 中的回调函数,如果系统绘制率是 60Hz,那么回调函数就每16.7ms 被执行一次,如果绘制频率是75Hz,那么这个间隔时间就变成了 1000/75=13.3ms。
另外它可以自动调节频率。如果callback工作太多无法在一帧内完成会自动降低为30fps。虽然降低了,但总比掉帧好。
与setTimeout动画对比的话,有以下几点优势
什么时候调用呢
规范中似乎是这么去定义的:
这样子分析的话,似乎很合理嘛,为什么要在重新渲染前去调用呢?因为rAF作为官方推荐的一种做流畅动画所应该使用的API,做动画不可避免的去操作DOM,而如果是在渲染后去修改DOM的话,那就只能等到下一轮渲染机会的时候才能去绘制出来了,这样子似乎不合理。
至于宏任务,微任务,这可以说起来就要展开篇幅了,暂时不在这里梳理了。
rAF与节流相比
跟
_.throttle(dosomething, 16)
等价。它是高保真的,如果追求更好的精确度的话,可以用浏览器原生的 API 。可以使用 rAF API 替换 throttle 方法,考虑一下优缺点:
优点
缺点
根据经验,如果 JavaScript 方法需要绘制或者直接改变属性,我会选择
requestAnimationFrame
,只要涉及到重新计算元素位置,就可以使用它。涉及到 AJAX 请求,添加/移除 class (可以触发 CSS 动画),我会选择
_.debounce
或者_.throttle
,可以设置更低的执行频率(例子中的200ms 换成16ms)。11. 能不能实现图片的懒加载
关于scrollTop,offsetTop,scrollLeft,offsetLeft用法介绍,点这里
原理思路
img dom
scroll
事件当然了,为了用户的体验更加,默认的情况下,设置一个占位图
本次测试代码
CSS代码👇
HTML👇
第一种方式
clientHeight-scrollTop-offsetTop
直接上我运行的代码👇
第二种方式
使用
element.getBoundingClientRect()
API 直接得到 top 值。代码👇
好像也差不多,不知道是不是我写的方式有问题(●'◡'●),感觉差不多
来看看效果吧,我给这个事件加了一个节流,这样子操作看起来就更好了。
12. 说一说你对Cookie localStorage sessionStorage
Cookie
得扯一下
HTTP是一个无状态的协议
,这里主要指的是HTTP1.x版本,简单的可以理解为即使同一个客户端连续两次发送请求给服务器,服务器也无法识别这个同一个客户端发的请求,导致的问题,比如现实生活中你加入一个商品到购物车,但是因为无法识别同一个客户端,你刷新页面的话就🤭为了解决 HTTP 无状态导致的问题(HTTP1.x),后来出现了 Cookie。
Cookie存放在本地的好处就在于即使你关闭了浏览器,Cookie 依然可以生效。
Cookie设置
怎么去设置呢?简单来说就是👇
Cookie指令
在下面这张图里我们可以看到 Cookies 相关的一些属性👇
这里主要说一些大家可能没有注意的点:
Name/Value
用 JavaScript 操作 Cookie 的时候注意对 Value 进行编码处理。
Expires/Max-Age
Expires 用于设置 Cookie 的过期时间。比如:
Max-Age 用于设置在 Cookie 失效之前需要经过的秒数。比如:
假如 Expires 和 Max-Age 都存在,Max-Age 优先级更高。
Domain
Domain 指定了 Cookie 可以送达的主机名。假如没有指定,那么默认值为当前文档访问地址中的主机部分(但是不包含子域名)。
在这里注意的是,不能跨域设置 Cookie
Path
Path 指定了一个 URL 路径,这个路径必须出现在要请求的资源的路径中才可以发送 Cookie 首部。比如设置
Path=/docs
,/docs/Web/
下的资源会带 Cookie 首部,/test
则不会携带 Cookie 首部。Domain 和 Path 标识共同定义了 Cookie 的作用域:即 Cookie 应该发送给哪些 URL。
Secure属性
标记为 Secure 的 Cookie 只应通过被HTTPS协议加密过的请求发送给服务端。使用 HTTPS 安全协议,可以保护 Cookie 在浏览器和 Web 服务器间的传输过程中不被窃取和篡改。
HTTPOnly
设置 HTTPOnly 属性可以防止客户端脚本通过 document.cookie 等方式访问 Cookie,有助于避免 XSS 攻击。
SameSite
SameSite 属性可以让 Cookie 在跨站请求时不会被发送,从而可以阻止跨站请求伪造攻击(CSRF)。
后面讲CSRF攻击会将讲到,这里过。
这个属性值修改有什么影响呢?
从上图可以看出,对大部分 web 应用而言,Post 表单,iframe,AJAX,Image 这四种情况从以前的跨站会发送三方 Cookie,变成了不发送。
Cookie 的作用
Cookie 主要用于以下三个方面:
Cookie 的缺点
从大小,安全,增加请求大小。
4KB
,只能用来存储少量的信息。localStorage 和 sessionStorage
在 web 本地存储场景上,cookie 的使用受到种种限制,最关键的就是存储容量太小和数据无法持久化存储。
在 HTML 5 的标准下,出现了 localStorage 和 sessionStorage 供我们使用。
异同点
操作方式
接下来我们来具体看看如何来操作
localStorage
和sessionStorage
接着进入相同的域名时就能拿到相应的值👇
从这里可以看出,
localStorage
其实存储的都是字符串,如果是存储对象需要调用JSON
的stringify
方法,并且用JSON.parse
来解析成对象。应用场景
logo
,存储Base64
格式的图片资源等;13. 聊一聊浏览器缓存
浏览器缓存是性能优化的一个重要手段,对于理解缓存机制而言也是很重要的,我们来梳理一下吧👇
强缓存
强缓存两个相关字段,Expires,Cache-Control。
强缓存分为两种情况,一种是发送HTTP请求,一种不需要发送。
首先检查强缓存,这个阶段**不需要发送HTTP请求。**通过查找不同的字段来进行,不同的HTTP版本所以不同。
Expires
Expires
即过期时间,时间是相对于服务器的时间而言的,存在于服务端返回的响应头中,在这个过期时间之前可以直接从缓存里面获取数据,无需再次请求。比如下面这样:表示该资源在2020年
7月29日11:10:23
过期,过期时就会重新向服务器发起请求。这个方式有一个问题:服务器的时间和浏览器的时间可能并不一致,所以HTTP1.1提出新的字段代替它。
Cache-Control
HTTP1.1版本中,使用的就是该字段,这个字段采用的时间是过期时长,对应的是max-age。
上面代表该资源返回后6000秒,可以直接使用缓存。
当然了,它还有其他很多关键的指令,梳理了几个重要的👇
注意点:
协商缓存
强缓存失效后,浏览器在请求头中携带响应的
缓存Tag
来向服务器发送请求,服务器根据对应的tag,来决定是否使用缓存。缓存分为两种,Last-Modified 和 ETag。两者各有优势,并不存在谁对谁有
绝对的优势
,与上面所讲的强缓存两个Tag所不同。Last-Modified
这个字段表示的是最后修改时间。在浏览器第一次给服务器发送请求后,服务器会在响应头中加上这个字段。
浏览器接收到后,如果再次请求,会在请求头中携带
If-Modified-Since
字段,这个字段的值也就是服务器传来的最后修改时间。服务器拿到请求头中的
If-Modified-Since
的字段后,其实会和这个服务器中该资源的最后修改时间
对比:ETag
ETag是服务器根据当前文件的内容,对文件生成唯一的标识,比如MD5算法,只要里面的内容有改动,这个值就会修改,服务器通过把响应头把该字段给浏览器。
浏览器接受到ETag值,会在下次请求的时候,将这个值作为If-None-Match这个字段的内容,发给服务器。
服务器接收到If-None-Match后,会跟服务器上该资源的ETag进行比对👇
两者对比
Last-Modified
优于ETag
,Last-Modified
记录的是时间点,而Etag
需要根据文件的MD5算法生成对应的hash值。ETag
优于Last-Modified
。ETag
按照内容给资源带上标识,能准确感知资源变化,Last-Modified
在某些场景并不能准确感知变化,比如👇最后,如果两种方式都支持的话,服务器会优先考虑
ETag
。缓存位置
接下来我们考虑使用缓存的话,缓存的位置在哪里呢?
浏览器缓存的位置的话,可以分为四种,优先级从高到低排列分别👇
Service Worker
这个应用场景比如PWA,它借鉴了Web Worker思路,由于它脱离了浏览器的窗体,因此无法直接访问DOM。它能完成的功能比如:
离线缓存
、消息推送
和网络代理
,其中离线缓存
就是Service Worker Cache。Memory Cache
指的是内存缓存,从效率上讲它是最快的,从存活时间来讲又是最短的,当渲染进程结束后,内存缓存也就不存在了。
Disk Cache
存储在磁盘中的缓存,从存取效率上讲是比内存缓存慢的,优势在于存储容量和存储时长。
Disk Cache VS Memory Cache
两者对比,主要的策略👇
内容使用率高的话,文件优先进入磁盘
比较大的JS,CSS文件会直接放入磁盘,反之放入内存。
Push Cache
推送缓存,这算是浏览器中最后一道防线吧,它是
HTTP/2
的内容。具体我也不是很清楚,有兴趣的可以去了解。总结
Cache-Control
, 尝鲜,看强缓存是否可用If-Modified-Since
或者If-None-Match
字段检查资源是否更新14. 说一说从输入URL到页面呈现发生了什么?
一旦问这个问题的话,我觉得肯定是一个非常深的问题了,无论从深度还是广度上,要真的答好这个题目,或者梳理清楚的话,挺难的,毕竟一个非常综合性的问题,我作为一个刚刚入门的小白,只能梳理部分知识,更深的知识可以去看看参考链接。
那么我们就开始吧,假设你输入的内容是👇
👇👇👇
网络请求
1. 构建请求
首先,浏览器构建请求行信息(如下所示),构建好后,浏览器准备发起网络请求👇
2. 查找缓存
在真正发起网络请求之前,浏览器会先在浏览器缓存中查询是否有要请求的文件。
先检查强缓存,如果命中的话直接使用,否则进入下一步,强缓存的知识点,上面👆梳理过了。
3. DNS解析
输入的域名的话,我们需要根据域名去获取对应的
ip地址
。 这个过程需要依赖一个服务系统,叫做是DNS域名解析
, 从查找到获取到具体IP的过程叫做是DNS解析
。关于DNS篇,可以看看阮一峰的网络日志
首先,浏览器提供了DNS数据缓存功能,如果一个域名已经解析过了,那么就会把解析的结果缓存下来,下次查找的话,直接去缓存中找,不需要结果DNS解析。
解析过程总结如下👇
首先查看是否有对应的域名缓存,有的话直接用缓存的ip访问
如果缓存中没有,则去查找hosts文件 一般在
c:\windows\system32\drivers\etc\hosts
如果hosts文件里没找到想解析的域名,则将域名发往自己配置的dns服务器,也叫本地dns服务器。
如果本地dns服务器有相应域名的记录,则返回记录。
如果电脑自己的服务器没有记录,会去找根服务器。根服务器全球只要13台,回去找其中之一,找了根服务器后,根服务器会根据请求的域名,返回对应的“顶级域名服务器”,如:
顶级域服务器收到请求,会返回二级域服务器的地址
www.xxx.edu.cn
,则顶级域名服务器再转发给负责.edu.cn
域的二级服务器以此类推,最终会发到负责锁查询域名的,最精确的那台dns,可以得到查询结果。
最后一步,本地dns服务器,把最终的解析结果,返回给客户端,对客户端来讲,只是一去一回的事,客户端并不知道本地dns服务器经过了千山万水。
以上就是大概的过程了,有兴趣的话,可以仔细去看看。
建立TCP链接
我们所了解的就是👉Chrome 在同一个域名下要求同时最多只能有 6 个 TCP 连接,超过 6 个的话剩下的请求就得等待。
那么我们假设不需要等待,我们进入了TCP连接的建立阶段。
建立
TCP连接
经历下面三个阶段:从上面看得出来,TCP 连接通过什么手段来保证数据传输的可靠性,一是
三次握手
确认连接,二是数据包校验
保证数据到达接收方,三是通过四次挥手
断开连接。深入理解的话,可以看看对应的文章,掘金上面很多文章都有深入了解,这里就不梳理了。
发送HTTP请求
TCP连接完成后,接下来就可以与服务器通信了,也就是我们经常说的发送HTTP请求。
发送HTTP请求的话,需要携带三样东西:请求行,请求头,请求体。
我们看看大概是是什么样子的吧👇
最后就是请求体,请求体的话只有在
POST
请求场景下存在,常见的就是表单提交
网络响应
HTTP 请求到达服务器,服务器进行对应的处理。最后要把数据传给浏览器,也就是通常我们说的返回网络响应。
跟请求部分类似,网络响应具有三个部分:响应行、响应头和响应体。
响应行类似下面这样👇
对应的响应头数据是怎么样的呢?我们来举个例子看看👇
接下来,我们数据拿到了,你认为就会断开TCP连接吗?
这个的看响应头中的Connection字段。上面的字段值为close,那么就会断开,一般情况下,HTTP1.1版本的话,通常请求头会包含Connection: Keep-Alive表示建立了持久连接,这样
TCP
连接会一直保持,之后请求统一站点的资源会复用这个连接。上面的情况就会断开
TCP
连接,请求-响应流程结束。到这里的话,网络请求就告一段落了,接下来的内容就是渲染流程了👇
渲染阶段
较为专业的术语总结为以下阶段:
关于渲染流程的话,可以看我之前总结的一篇✅✅✅
[1.1W字]写给女友的秘籍-浏览器工作原理(渲染流程)篇
15. 谈一谈你对重排和重绘理解
关于重排和重绘,可以上面的知识点去梳理,也就是渲染阶段,里面也梳理了部分的点,(●'◡'●)
偷个懒,看下面的文章噢👇
[1.1W字]写给女友的秘籍-浏览器工作原理(渲染流程)篇
16. 谈一谈跨域,同源策略,以及跨域解决方案
什么是跨域
跨域,是指浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对JavaScript实施的安全限制。
同源策略
同源策略是一个安全策略。所谓的同源,指的是协议,域名,端口相同。
浏览器处于安全方面的考虑,只允许本域名下的接口交互,不同源的客户端脚本,在没有明确授权的情况下,不能读写对方的资源。
限制了一下行为:
解决方案
当然了,我梳理了几个我觉得工作中常用的,其他的自行去了解。
jsonp跨域
利用script标签没有跨域限制的漏洞,网页可以拿到从其他来源产生动态JSON数据,当然了JSONP请求一定要对方的服务器做支持才可以。
与AJAX对比
JSONP和AJAX相同,都是客户端向服务器发送请求,从服务器获取数据的方式。但是AJAX属于同源策略,JSONP属于非同源策略(跨域请求)
JSONP优点
兼容性比较好,可用于解决主流浏览器的跨域数据访问的问题。缺点就是仅支持get请求,具有局限性,不安全,可能会受到XSS攻击。
思路👇
当然,jquery也支持jsonp的实现方式
JSONP优点
JSONP缺点
跨域资源共享 CORS
上面是引用,你要记住的关键点👇
CORS 需要浏览器和后端同时支持。IE 8 和 9 需要通过 XDomainRequest 来实现。
请求分为简单请求和非简单请求,所以我们的了解这两种情况。
简单请求
满足下面两个条件,就属于简单请求👇
条件1:使用下列方法之一:
条件2:Content-Type 的值仅限于下列三者之一👇
请求中的任意 XMLHttpRequestUpload 对象均没有注册任何事件监听器;
XMLHttpRequestUpload 对象可以使用 XMLHttpRequest.upload 属性访问。
复杂请求
不符合以上条件的请求就肯定是复杂请求了。 复杂请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求,该请求是 option 方法的,通过该请求来知道服务端是否允许跨域请求。
直接上一个例子吧👇 看看一个完整的复杂请求吧,并且介绍一下CORS请求的字段。
上述代码由
http://localhost:3000/index.html
向http://localhost:4000/
跨域请求,正如我们上面所说的,后端是实现 CORS 通信的关键。上述的例子,一定对你会有所帮助的,这块代码,是跟着
浪里行舟
代码来的,参考处注明了出处。与JSONP对比
WebSocket协议跨域
Websocket是HTML5的一个持久化的协议,它实现了浏览器与服务器的全双工通信,同时也是跨域的一种解决方案。
我们先来看个例子👇
本地文件socket.html向
localhost:3000
发生数据和接受数据👇后端部分👇
如果 你想去尝试的话,建议可以去玩一玩
Socket.io
,nginx代理跨域
17. 谈一谈你对XSS攻击理解
什么是 XSS 攻击
XSS 全称是
Cross Site Scripting
,为了与CSS
区分开来,故简称XSS
,翻译过来就是“跨站脚本”。XSS是指黑客往 HTML 文件中或者 DOM 中注入恶意脚本,从而在用户浏览页面时利用注入的恶意脚本对用户实施攻击的一种手段。
最开始的时候,这种攻击是通过跨域来实现的,所以叫“跨域脚本”。发展到现在,往HTML文件中中插入恶意代码方式越来越多,所以是否跨域注入脚本已经不是唯一的注入手段了,但是 XSS 这个名字却一直保留至今。
注入恶意脚本可以完成这些事情:
一般的情况下,XSS攻击有三种实现方式
存储型 XSS 攻击
从图上看,存储型 XSS 攻击大致步骤如下:
比如常见的场景:
在评论区提交一份脚本代码,假设前后端没有做好转义工作,那内容上传到服务器,在页面渲染的时候就会
直接执行
,相当于执行一段未知的JS代码。这就是存储型 XSS 攻击。反射型 XSS 攻击
反射型 XSS 攻击指的就是恶意脚本作为网络请求的一部分,随后网站又把恶意的JavaScript脚本返回给用户,当恶意 JavaScript 脚本在用户页面中被执行时,黑客就可以利用该脚本做一些恶意操作。
举个例子:
如上,服务器拿到后解析参数query,最后将内容返回给浏览器,浏览器将这些内容作为HTML的一部分解析,发现是Javascript脚本,直接执行,这样子被XSS攻击了。
这也就是反射型名字的由来,将恶意脚本作为参数,通过网络请求,最后经过服务器,在反射到HTML文档中,执行解析。
主要注意的就是,服务器不会存储这些恶意的脚本,这也算是和存储型XSS攻击的区别吧。
基于 DOM 的 XSS 攻击
基于 DOM 的 XSS 攻击是不牵涉到页面 Web 服务器的。具体来讲,黑客通过各种手段将恶意脚本注入用户的页面中,在数据传输的时候劫持网络数据包
常见的劫持手段有:
阻止 XSS 攻击的策略
以上讲述的XSS攻击原理,都有一个共同点:让恶意脚本直接在浏览器执行。
针对三种不同形式的XSS攻击,有以下三种解决办法
对输入脚本进行过滤或转码
对用户输入的信息过滤或者是转码
举个例子👇
<script>alert('你受到XSS攻击了')</script>转码后👇
这样的代码在 html 解析的过程中是无法执行的。
当然了对于
<script>
、<img>
、<a>
等关键字标签也是可以过来的,效果如下👇最后什么都没有剩下了
利用 CSP
该安全策略的实现基于一个称作
Content-Security-Policy
的 HTTP 首部。可以移步MDN,有更加规范的解释。我在这里就是梳理一下吧。
CSP,即浏览器中的内容安全策略,它的核心思想大概就是服务器决定浏览器加载哪些资源,具体来说有几个功能👇
利用 HttpOnly
由于很多 XSS 攻击都是来盗用 Cookie 的,因此还可以通过使用 HttpOnly 属性来保护我们 Cookie 的安全。这样子的话,JavaScript 便无法读取 Cookie 的值。这样也能很好的防范 XSS 攻击。
通常服务器可以将某些 Cookie 设置为 HttpOnly 标志,HttpOnly 是服务器通过 HTTP 响应头来设置的,下面是打开 Google 时,HTTP 响应头中的一段:
总结
XSS
攻击是指浏览器中执行恶意脚本, 然后拿到用户的信息进行操作。主要分为存储型
、反射型
和文档型
。防范的措施包括:<script>
、<img>
、<a>
标签除了以上策略之外,我们还可以通过添加验证码防止脚本冒充用户提交危险操作。而对于一些不受信任的输入,还可以限制其输入长度,这样可以增大 XSS 攻击的难度。
18. 能不能说一说CSRF攻击
什么是CSRF攻击呢?
CSRF 英文全称是
Cross-site request forgery
,所以又称为“跨站请求伪造”,是指黑客引诱用户打开黑客的网站,在黑客的网站中,利用用户的登录状态发起的跨站请求。简单来讲,CSRF 攻击就是黑客利用了用户的登录状态,并通过第三方的站点来做一些坏事。一般的情况下,点开一个诱导你的链接,黑客会在你不知情的时候做哪些事情呢
1. 自动发起 Get 请求
黑客网页里面可能有一段这样的代码👇
在受害者访问含有这个img的页面后,浏览器会自动向
http://bank.example/withdraw?account=xiaoming&amount=10000&for=hacker
发出一次HTTP请求。bank.example
就会收到包含受害者登录信息的一次跨域请求。2. 自动发起 POST 请求
黑客网页中有一个表单,自动提交的表单👇
访问该页面后,表单会自动提交,相当于模拟用户完成了一次POST操作。
同样也会携带相应的用户 cookie 信息,让服务器误以为是一个正常的用户在操作,让各种恶意的操作变为可能。
3. 引诱用户点击链接
这种需要诱导用户去点击链接才会触发,这类的情况比如在论坛中发布照片,照片中嵌入了恶意链接,或者是以广告的形式去诱导,比如:
点击后,自动发送 get 请求,接下来和
自动发 GET 请求
部分同理。以上三种情况,就是CSRF攻击原理,跟XSS对比的话,CSRF攻击并不需要将恶意代码注入HTML中,而是跳转新的页面,利用服务器的验证漏洞和用户之前的登录状态来模拟用户进行操作
防护策略
其实我们可以想到,黑客只能借助受害者的
**cookie**
骗取服务器的信任,但是黑客并不能凭借拿到cookie,也看不到 cookie的内容。另外,对于服务器返回的结果,由于浏览器同源策略的限制,黑客也无法进行解析。用户操作限制——验证码机制
方法:添加验证码来识别是不是用户主动去发起这个请求,由于一定强度的验证码机器无法识别,因此危险网站不能伪造一个完整的请求。
1. 验证来源站点
在服务器端验证请求来源的站点,由于大量的CSRF攻击来自第三方站点,因此服务器跨域禁止来自第三方站点的请求,主要通过HTTP请求头中的两个Header
这两个Header在浏览器发起请求时,大多数情况会自动带上,并且不能由前端自定义内容。
服务器可以通过解析这两个Header中的域名,确定请求的来源域。
其中,Origin只包含域名信息,而Referer包含了
具体
的 URL 路径。在某些情况下,这两者都是可以伪造的,通过
AJax
中自定义请求头即可,安全性略差。2. 利用Cookie的SameSite属性
可以看看MDN对此的解释
SameSite
可以设置为三个值,Strict
、Lax
和None
。Strict
模式下,浏览器完全禁止第三方请求携带Cookie。比如请求sanyuan.com
网站只能在sanyuan.com
域名当中请求才能携带 Cookie,在其他网站请求都不能。Lax
模式,就宽松一点了,但是只能在get 方法提交表单
况或者a 标签发送 get 请求
的情况下可以携带 Cookie,其他情况均不能。3. CSRF Token
前面讲到CSRF的另一个特征是,攻击者无法直接窃取到用户的信息(Cookie,Header,网站内容等),仅仅是冒用Cookie中的信息。
那么我们可以使用Token,在不涉及XSS的前提下,一般黑客很难拿到Token。
可以看看这篇文章,将了Token是怎么操作的👉彻底理解cookie,session,token
Token(令牌)做为Web领域验证身份是一个不错的选择,当然了,JWT有兴趣的也可以去了解一下。
Token步骤如下:
第一步:将CSRF Token输出到页面中
第二步:页面提交的请求携带这个Token
第三步:服务器验证Token是否正确
非常感兴趣的,可以仔细去阅读一下相关的文章,Token是如何加密的,又是如何保证不被攻击者获取道。
总结
CSRF(Cross-site request forgery), 即跨站请求伪造,本质是冲着浏览器分不清发起请求是不是真正的用户本人,所以防范的关键在于在请求中放入黑客所不能伪造的信息。从而防止黑客伪造一个完整的请求欺骗服务器。
防范措施:验证码机制,验证来源站点,利用Cookie的SameSite属性,CSRF Token
参考
❤️ 感谢大家
如果你觉得这篇内容对你挺有有帮助的话:
The text was updated successfully, but these errors were encountered: