• 技术文章 >web前端 >前端问答

    看看这些关于浏览器的面试题,你能答对几个?

    青灯夜游青灯夜游2022-03-23 10:39:59转载191
    本篇文章给大家分享一些关于浏览器的面试题,看看你能回答几个?对对答案解析,看看能答对几个!

    1.常见的浏览器内核有哪些?

    浏览器的内核可以分成两部分:

    渲染引擎JS引擎注意:我们常说的浏览器内核就是指渲染引擎

    由于JS引擎越来越独立,内核就指的只是渲染引擎了,渲染引擎主要用来请求网络页面资源解析排版后呈现给用户

    浏览器/RunTime内核(渲染引擎)JavaScript 引擎
    ChromeBlink(28~) Webkit(Chrome 27)V8
    FireFoxGeckoSpiderMonkey
    SafariWebkitJavaScriptCore
    EdgeEdgeHTMLChakra(For JavaScript)
    IETridentChakra(For JScript)
    OperaPresto->blinkLinear A(4.0-6.1)/ Linear B(7.0-9.2)/ Futhark(9.5-10.2)/ Carakan(10.5-)
    Node.js-V8

    2.浏览器的主要组成部分有哪些?

    注意:与大多数浏览器不同的是,谷歌(Chrome)浏览器的每个标签页都分别对应一个呈现引擎实例。每个标签页都是一个独立的进程

    1.png

    3.说一说从输入URL到页面呈现发生了什么?

    这个题可以说是面试最常见也是一道可以无限难的题了,一般面试官出这道题就是为了考察你的前端知识深度。

    1、浏览器接受URL开启网络请求线程(涉及到:浏览器机制,线程与进程等)

    2、开启网络线程到发出一个完整的http请求(涉及到:DNS查询,TCP/IP请求,5层网络协议等)

    3、从服务器接收到请求到对应后台接受到请求(涉及到:负载均衡,安全拦截,后台内部处理等)

    4、后台与前台的http交互(涉及到:http头,响应码,报文结构,cookie等)

    5、缓存问题(涉及到:http强缓存与协商缓存,缓存头,etag,expired,cache-control等)

    6、浏览器接受到http数据包后的解析流程(涉及到html词法分析,解析成DOM树,解析CSS生成CSSOM树,合并生成render渲染树。然后layout布局,painting渲染,复合图层合成,GPU绘制,外链处理等)

    7、css可视化模型(涉及到:元素渲染规则,如:包含块,控制框,BFC,IFC等)

    8、JS引擎解析过程(涉及到:JS解析阶段,预处理阶段,执行阶段生成执行上下文,VO(全局对象),作用域链,回收机制等)

    你会发现一个简单的输入URL到页面呈现,之间会发生这么多过程,是不是瞬间觉得崩溃了?(别急,这一章我们不讲这么深,先教你如何回答这个问题,后面这一节单独出文章讲)

    2.png

    4.浏览器是如何解析代码的?

    解析HTML

    HTML是逐行解析的,浏览器的渲染引擎会将HTML文档解析并转换成DOM节点。

    解析CSS

    浏览器会从右往左解析CSS选择器

    我们知道DOM树与CSSOM树合并成render树,实际上是将CSSOM附着到DOM树上,因此需要根据选择器提供的信息对DOM树进行遍历。

    我们看一个例子:

    <style>
    .nav .title span {color:blue}
    </style>
    
    <div class='nav'>
      <div class='title'>
        <span>南玖</span>
      </div>
      <div class="sub_title">前端</header>
    </div>

    从右至左的匹配:

    解析JS

    在浏览器中有一个js解析器的工具,专门用来解析我们的js代码。

    当浏览器遇到js代码时,立马召唤“js解析器”出来工作。

    解析器会找到js当中的所有变量、函数、参数等等,并且把变量赋值为未定义(undefined)。

    把函数取出来成为一个函数块,然后存放到仓库当中。这件事情做完了之后才开始逐行解析代码(由上向下,由左向右),然后再去和仓库进行匹配。

    5.DOMContentLoaded与load的区别?

    6.浏览器重绘域重排的区别?

    重绘不一定导致重排,但重排一定绘导致重绘

    如何触发重绘和重排?

    任何改变用来构建渲染树的信息都会导致一次重排或重绘:

    如何避免重绘或重排?

    7.为什么JS是单线程的?

    这主要与JS的用途有关,JS作为浏览器的脚本语言,最初主要是实现用户与浏览器的交互,以及操作DOM。这就决定了它只能是单线程,否则会带来许多复杂的同步问题。

    举个例子: 如果JS是多线程的,其中一个线程要修改一个DOM元素,另外一个线程想要删除这个DOM元素,这时候浏览器就不知道该听谁的。所以为了避免复杂性,从一诞生,JavaScript就被设计成单线程。

    为了利用多核CPU的计算能力,HTML5提出Web Worker标准,允许JavaScript脚本创建多个线程,但是子线程完全受主线程控制,且不得操作DOM。所以,这个新标准并没有改变JavaScript单线程的本质

    8.CSS加载会阻塞DOM吗?

    先上结论

    • CSS不会阻塞DOM的解析,但会阻塞DOM的渲染
    • CSS会阻塞JS执行,但不会阻塞JS文件的下载

    CSSOM的作用

    由之前讲到的浏览器渲染流程我们可以看出:

    JS需要等待CSS的下载,这是为什么呢?(CSS阻塞DOM执行)

    如果JS脚本的内容是获取元素的样式,那它就必然依赖CSS。因为浏览器无法感知JS内部到底想干什么,为避免样式获取,就只好等前面所有的样式下载完毕再执行JS。但JS文件与CSS文件下载是并行的,CSS文件会在后面的JS文件执行前先加载执行完毕,所以CSS会阻塞后面JS的执行

    避免白屏,提高CSS的加载速度

    9.JS会阻塞页面吗?

    先上结论

    JS会阻塞DOM的解析,因此也就会阻塞页面的加载

    这也是为什么我们常说要把JS文件放在最下面的原因

    由于 JavaScript 是可操纵 DOM 的,如果在修改这些元素属性同时渲染界面(即 JavaScript 线程和 UI 线程同时运行),那么渲染线程前后获得的元素数据就可能不一致了。

    因此为了防止渲染出现不可预期的结果,浏览器设置 **「GUI 渲染线程与 JavaScript 引擎为互斥」**的关系。

    当 JavaScript 引擎执行时 GUI 线程会被挂起,GUI 更新会被保存在一个队列中等到引擎线程空闲时立即被执行。

    当浏览器在执行 JavaScript 程序的时候,GUI 渲染线程会被保存在一个队列中,直到 JS 程序执行完成,才会接着执行。

    因此如果 JS 执行的时间过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞的感觉。

    10.defer和async的区别?

    11.浏览器的垃圾回收机制

    垃圾回收是一种自动的内存管理机制。当计算机上的动态内存不再需要时,就应该予以释放。

    需要注意的是,自动的意思是浏览器可以自动帮助我们回收内存垃圾,但并不代表我们不用关心内存管理,如果操作不当,JavaScript中仍然会出现内存溢出的情况,造成系统崩溃。

    由于字符串,数组,对象等都没有固定大小,因此需要当它们大小已知时,才能对他们进行动态的存储分配。JavaScript程序每次创建字符串,数组或对象时,解释器都必须分配内存来存储那个实体。

    JavaScript解释器可以检测到何时程序不在使用一个对象了,当它确定这个对象是无用的时候,他就知道不再需要这个对象了,就可以把它占用的内存释放掉了。

    浏览器通常采用的垃圾回收有两种方法:标记清除引用计数

    标记清除

    这是JavaScript中最常用的垃圾回收方式

    从2012年起,所有现代浏览器都使用了标记清除的垃圾回收方法,除了低版本IE还是采用的引用计数法。

    那么什么叫标记清除呢?

    JavaScript中有一个全局对象,定期的,垃圾回收器将从这个全局对象开始,找出所有从这个全局对象开始引用的对象,再找这些对象引用的对象...对这些活跃的对象标记,这是标记阶段。清楚阶段就是清楚那些没有被标记的对象。

    标记清除有一个问题,就是在清除之后,内存空间是不连续的,即出现了内存碎片。如果后面需要一个比较大的连续的内存空间,那将不能满足要求。而标记整理 方法可以有效德地解决这个问题。

    在标记的过程中,引入了概念:三色标记法,三色为:

    标记整理:

    标记阶段与标记清除法没什么区别,只是标记结束后,标记整理法会将存活的对象向内存的一边移动,最后清理掉边界内存。

    引用计数

    引用计数的含义是跟踪记录每个值被引用的次数。当一个变量A被赋值时,这个值的引用次数就是1,当变量A重新赋值后,则之前那个值的引用次数就减1。当引用次数变成0时,则说明没有办法再访问这个值了,所以就可以清除这个值占用的内存了。

    大多数浏览器已经放弃了这种回收方式

    内存泄漏

    为避免内存泄漏,一旦数据不再使用,最好通过将其值设为null来释放其引用,这个方法叫做接触引用

    哪些情况会造成内存泄漏?如何避免?

    以 Vue 为例,通常有这些情况:

    解决办法:beforeDestroy 中及时销毁

    浏览器中不同类型变量的内存都是何时释放的?

    12.说一说浏览器的缓存机制?

    认识浏览器缓存

    当浏览器请求一个网站时,会加载各种资源,对于一些不经常变动的资源,浏览器会将他们保存在本地内存中,下次访问时直接加载这些资源,提高访问速度。

    如何知道资源是请求的服务器还是读取的缓存呢?

    3.png

    看上面这张图,有些资源的size值是大小,有些是from disk cache,有些是from memory cache,显示大小的是请求的服务器资源,而显示后面两种的则是读取的缓存。

    -memory cachedisk cache
    相同点只能存储一些派生类资源文件只能存储一些派生类资源文件
    不同点退出进程时数据会被清除退出进程时数据不会被清除
    存储资源一般脚本、字体、图片会存在内存当中一般非脚本会存在内存当中,如css等

    浏览器缓存分类

    浏览器在向服务器请求资源时,首先判断是否命中强缓存,没命中再判断是否命中协商缓存

    强缓存

    浏览器在加载资源时,会先根据本地缓存资源的header中判断是否命中强缓存,如果命中则直接使用缓存中的资源,不会再向服务器发送请求。 (这里的header中的信息指的是 expirescache-control

    该字段是 http1.0 时的规范,它的值为一个绝对时间的 GMT 格式的时间字符串,比如 Expires:Mon,18 Oct 2066 23:59:59 GMT。这个时间代表着这个资源的失效时间,在此时间之前,即命中缓存。这种方式有一个明显的缺点,由于失效时间是一个绝对时间,所以当服务器与客户端时间偏差较大时,就会导致缓存混乱。所以这种方式很快在后来的HTTP1.1版本中被抛弃了。

    Cache-Control 是 http1.1 时出现的 header 信息,主要是利用该字段的 max-age 值来进行判断,它是一个相对时间,例如 Cache-Control:max-age=3600,代表着资源的有效期是 3600 秒。cache-control 除了该字段外,还有下面几个比较常用的设置值:

    no-cache:需要进行协商缓存,发送请求到服务器确认是否使用缓存。

    no-store:禁止使用缓存,每一次都要重新请求数据。

    public:可以被所有的用户缓存,包括终端用户和 CDN 等中间代理服务器。

    private:只能被终端用户的浏览器缓存,不允许 CDN 等中继缓存服务器对其缓存。

    Cache-Control 与 Expires 可以在服务端配置同时启用,同时启用的时候 Cache-Control 优先级高。

    协商缓存

    当强缓存没命中时,浏览器会发送一个请求到服务器,服务器根据 header 中的信息来判断是否命中协商缓存。如果命中,则返回304 ,告诉浏览器资源未更新,可以使用本地缓存。 (这里的header信息指的是Last-Modify/If-Modify-SinceETag/If-None-Match

    浏览器第一次请求一个资源的时候,服务器返回的 header 中会加上 Last-Modify,Last-modify 是一个时间标识该资源的最后修改时间。

    当浏览器再次请求该资源时,request 的请求头中会包含 If-Modify-Since,该值为缓存之前返回的 Last-Modify。服务器收到 If-Modify-Since 后,根据资源的最后修改时间判断是否命中缓存。

    如果命中缓存,则返回 304,并且不会返回资源内容,并且不会返回 Last-Modify。

    缺点:

    短时间内资源发生了改变,Last-Modified 并不会发生变化。

    周期性变化。如果这个资源在一个周期内修改回原来的样子了,我们认为是可以使用缓存的,但是 Last-Modified 可不这样认为,因此便有了 ETag。

    与 Last-Modify/If-Modify-Since 不同的是,Etag/If-None-Match 返回的是一个校验码。ETag 可以保证每一个资源是唯一的,资源变化都会导致 ETag 变化。服务器根据浏览器上送的 If-None-Match 值来判断是否命中缓存。

    与 Last-Modified 不一样的是,当服务器返回 304 Not Modified 的响应时,由于 ETag 重新生成过,response header 中还会把这个 ETag 返回,即使这个 ETag 跟之前的没有变化。

    Last-Modified 与 ETag 是可以一起使用的,服务器会优先验证 ETag,一致的情况下,才会继续比对 Last-Modified,最后才决定是否返回 304。

    总结

    当浏览器访问一个已经访问过的资源是,它的步骤是:

    1.先看是否命中强缓存,命中?的话直接使用缓存

    2.没命中强缓存,则会发送请求到服务器看是否命中?协商缓存

    3.如果命中了协商缓存,服务器会返回304告诉浏览器可以使用本地缓存

    4.没命中协商缓存,则服务器会返回新的资源给浏览器

    13.什么是浏览器的同源策略,以及跨域?

    同源策略

    同源策略是浏览器的一种自我保护行为。所谓的同源指的是:协议,域名,端口均要相同

    浏览器中大部分内容都是受同源策略限制的,但是以下三个标签不受限制:

    <img src="..." />
    <link href="..." />
    <script src="..."></script>

    跨域

    跨域指的是浏览器不能执行其它域名下的脚本。它是由浏览器的同源策略限制的。

    你可能会想跨域请求到底有没有发送到服务器?

    事实上,跨域请求时能够发送到服务器的,并且服务器也能过接受的请求并正常返回结果,只是结果被浏览器拦截了。

    跨域解决方案(列出几个常用的)

    它主要是利用script标签不受浏览器同源策略的限制,可以拿到从其他源传输过来的数据,需要服务端支持。

    优缺点:

    兼容性比较好,可用于解决主流浏览器的跨域数据访问的问题。缺点就是仅支持get请求,具有局限性,不安全,可能会受到XSS攻击。

    思路:

    // front
    function jsonp({ url, params, callback }) {
      return new Promise((resolve, reject) => {
        let script = document.createElement('script')
        window[callback] = function(data) {
          resolve(data)
          document.body.removeChild(script)
        }
        params = { ...params, callback } // wd=b&callback=show
        let arrs = []
        for (let key in params) {
          arrs.push(`${key}=${params[key]}`)
        }
        script.src = `${url}?${arrs.join('&')}`
        document.body.appendChild(script)
      })
    }
    jsonp({
      url: 'http://localhost:3000/say',
      params: { wd: 'wxgongzhonghao' },
      callback: 'show'
    }).then(data => {
      console.log(data)
    })
    // server 借助express框架
    let express = require('express')
    let app = express()
    app.get('/say', function(req, res) {
      let { wd, callback } = req.query
      console.log(wd) // Iloveyou
      console.log(callback) // show
      res.end(`${callback}('关注前端南玖')`)
    })
    app.listen(3000)

    上面这段代码相当于向http://localhost:3000/say?wd=wxgongzhonghao&callback=show这个地址请求数据,然后后台返回show('关注前端南玖'),最后会运行show()这个函数,打印出'关注前端南玖'

    CORS(Cross-Origin Resource Sharing)跨域资源共享,定义了必须在访问跨域资源时,浏览器与服务器应该如何沟通。CORS背后的基本思想是使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功还是失败。

    CORS 需要浏览器和后端同时支持。IE 8 和 9 需要通过 XDomainRequest 来实现

    浏览器会自动进行 CORS 通信,实现 CORS 通信的关键是后端。只要后端实现了 CORS,就实现了跨域。

    服务端设置 Access-Control-Allow-Origin 就可以开启 CORS。 该属性表示哪些域名可以访问资源,如果设置通配符则表示所有网站都可以访问资源。

    虽然设置 CORS 和前端没什么关系,但是通过这种方式解决跨域问题的话,会在发送请求时出现两种情况,分别为简单请求复杂请求

    简单请求: (满足以下两个条件,就是简单请求)

    1.请求方法为以下三个之一:

    2.Content-Type的为以下三个之一:

    复杂请求:

    不是简单请求那它肯定就是复杂请求了。复杂请求的CORS请求,会在正式发起请求前,增加一次HTTP查询请求,称为预检 请求,该请求是option方法的,通过该请求来知道服务端是否允许该跨域请求。

    Nginx反向代理

    Nginx 反向代理的原理很简单,即所有客户端的请求都必须经过nginx处理,nginx作为代理服务器再将请求转发给后端,这样就规避了浏览器的同源策略。

    14.说说什么是XSS攻击

    什么是XSS?

    XSS 全称是 Cross Site Scripting,为了与css区分开来,所以简称XSS,中文叫作跨站脚本

    XSS是指黑客往页面中注入恶意脚本,从而在用户浏览页面时利用恶意脚本对用户实施攻击的一种手段。

    XSS能够做什么?

    XSS实现方式

    如何阻止XSS攻击?

    对输入脚本进行过滤或转码

    对用户输入的信息过滤或者转码,保证用户输入的内容不能在HTML解析的时候执行。

    利用CSP

    该安全策略的实现基于一个称作 Content-Security-Policy的HTTP首部。(浏览器内容安全策略)它的核心思想就是服务器决定浏览器加载那些资源。

    利用 HttpOnly

    由于很多 XSS 攻击都是来盗用 Cookie 的,因此还可以通过使用 HttpOnly 属性来保护我们 Cookie 的安全。这样子的话,JavaScript 便无法读取 Cookie 的值。这样也能很好的防范 XSS 攻击。

    通常服务器可以将某些 Cookie 设置为 HttpOnly 标志,HttpOnly 是服务器通过 HTTP 响应头来设置的,下面是打开 Google 时,HTTP 响应头中的一段:

    set-cookie: NID=189=M8l6-z41asXtm2uEwcOC5oh9djkffOMhWqQrlnCtOI; expires=Sat, 18-Apr-2020 06:52:22 GMT; path=/; domain=.google.com; HttpOnly

    对于不受信任的输入,可以限制输入长度

    15.说说什么是CSRF攻击?

    什么是CSRF攻击?

    CSRF 全称 Cross-site request forgery,中文为跨站请求伪造 ,攻击者诱导受害者进入第三方网站,在第三方网站中,向被攻击网站发送跨站请求。利用受害者在被攻击网站已经获取的注册凭证,绕过后台的用户验证,达到冒充用户对被攻击的网站执行某项操作的目的。 CSRF攻击就是黑客利用用户的登录状态,并通过第三方站点来干一些嘿嘿嘿的坏事

    几种常见的攻击类型

    1.GET类型的CSRF

    GET类型的CSRF非常简单,通常只需要一个HTTP请求:

     <img src="http://bank.example/withdraw?amount=10000&for=hacker" >

    在受害者访问含有这个img的页面后,浏览器会自动向http://bank.example/withdraw?account=xiaoming&amount=10000&for=hacker发出一次HTTP请求。bank.example就会收到包含受害者登录信息的一次跨域请求。

    2.POST类型的CSRF

    这种类型的CSRF利用起来通常使用的是一个自动提交的表单,如:

     <form action="http://bank.example/withdraw" method=POST>
        <input type="hidden" name="account" value="xiaoming" />
        <input type="hidden" name="amount" value="10000" />
        <input type="hidden" name="for" value="hacker" />
    </form>
    <script> document.forms[0].submit(); </script>

    访问该页面后,表单会自动提交,相当于模拟用户完成了一次POST操作。

    3.链接类型的CSRF

    链接类型的CSRF并不常见,比起其他两种用户打开页面就中招的情况,这种需要用户点击链接才会触发。这种类型通常是在论坛中发布的图片中嵌入恶意链接,或者以广告的形式诱导用户中招,攻击者通常会以比较夸张的词语诱骗用户点击,例如:

      <a href="http://test.com/csrf/withdraw.php?amount=1000&for=hacker" taget="_blank">
      重磅消息!!
      <a/>

    由于之前用户登录了信任的网站A,并且保存登录状态,只要用户主动访问上面的这个PHP页面,则表示攻击成功。

    CSRF的特点

    CSRF通常是跨域的,因为外域通常更容易被攻击者掌控。但是如果本域下有容易被利用的功能,比如可以发图和链接的论坛和评论区,攻击可以直接在本域下进行,而且这种攻击更加危险。

    防护策略

    黑客只能借助受害者的cookie 骗取服务器的信任,但是黑客并不能凭借拿到**「cookie」**,也看不到 **「cookie」的内容。另外,对于服务器返回的结果,由于浏览器「同源策略」**的限制,黑客也无法进行解析。

    这就告诉我们,我们要保护的对象是那些可以直接产生数据改变的服务,而对于读取数据的服务,则不需要进行CSRF的保护。而保护的关键,是 「在请求中放入黑客所不能伪造的信息」

    同源检测

    既然CSRF大多来自第三方网站,那么我们就直接禁止外域(或者不受信任的域名)对我们发起请求。

    那么问题来了,我们如何判断请求是否来自外域呢?

    在HTTP协议中,每一个异步请求都会携带两个Header,用于标记来源域名:

    这两个Header在浏览器发起请求时,大多数情况会自动带上,并且不能由前端自定义内容。 服务器可以通过解析这两个Header中的域名,确定请求的来源域。

    使用Origin Header确定来源域名

    在部分与CSRF有关的请求中,请求的Header中会携带Origin字段。字段内包含请求的域名(不包含path及query)。

    如果Origin存在,那么直接使用Origin中的字段确认来源域名就可以。

    但是Origin在以下两种情况下并不存在:

    使用Referer Header确定来源域名

    根据HTTP协议,在HTTP头中有一个字段叫Referer,记录了该HTTP请求的来源地址。 对于Ajax请求,图片和script等资源请求,Referer为发起请求的页面地址。对于页面跳转,Referer为打开页面历史记录的前一个页面地址。因此我们使用Referer中链接的Origin部分可以得知请求的来源域名。

    这种方法并非万无一失,Referer的值是由浏览器提供的,虽然HTTP协议上有明确的要求,但是每个浏览器对于Referer的具体实现可能有差别,并不能保证浏览器自身没有安全漏洞。使用验证 Referer 值的方法,就是把安全性都依赖于第三方(即浏览器)来保障,从理论上来讲,这样并不是很安全。在部分情况下,攻击者可以隐藏,甚至修改自己请求的Referer。

    2014年,W3C的Web应用安全工作组发布了Referrer Policy草案,对浏览器该如何发送Referer做了详细的规定。截止现在新版浏览器大部分已经支持了这份草案,我们终于可以灵活地控制自己网站的Referer策略了。新版的Referrer Policy规定了五种Referer策略:No Referrer、No Referrer When Downgrade、Origin Only、Origin When Cross-origin、和 Unsafe URL。之前就存在的三种策略:never、default和always,在新标准里换了个名称。他们的对应关系如下:

    策略名称属性值(新)属性值(旧)
    No Referrerno-Referrernever
    No Referrer When Downgradeno-Referrer-when-downgradedefault
    Origin Only(same or strict) originorigin
    Origin When Cross Origin(strict) origin-when-crossorigin-
    Unsafe URLunsafe-urlalways

    根据上面的表格因此需要把Referrer Policy的策略设置成same-origin,对于同源的链接和引用,会发送Referer,referer值为Host不带Path;跨域访问则不携带Referer。例如:aaa.com引用bbb.com的资源,不会发送Referer。

    设置Referrer Policy的方法有三种:

    上面说的这些比较多,但我们可以知道一个问题:攻击者可以在自己的请求中隐藏Referer。如果攻击者将自己的请求这样填写:

     <img src="http://bank.example/withdraw?amount=10000&for=hacker" referrerpolicy="no-referrer">

    那么这个请求发起的攻击将不携带Referer。

    另外在以下情况下Referer没有或者不可信:

    1.IE6、7下使用window.location.href=url进行界面的跳转,会丢失Referer。

    2.IE6、7下使用window.open,也会缺失Referer。

    3.HTTPS页面跳转到HTTP页面,所有浏览器Referer都丢失。

    4.点击Flash上到达另外一个网站的时候,Referer的情况就比较杂乱,不太可信。

    无法确认来源域名情况

    当Origin和Referer头文件不存在时该怎么办?如果Origin和Referer都不存在,建议直接进行阻止,特别是如果您没有使用随机CSRF Token(参考下方)作为第二次检查。

    如何阻止外域请求

    通过Header的验证,我们可以知道发起请求的来源域名,这些来源域名可能是网站本域,或者子域名,或者有授权的第三方域名,又或者来自不可信的未知域名。

    我们已经知道了请求域名是否是来自不可信的域名,我们直接阻止掉这些的请求,就能防御CSRF攻击了吗?

    且慢!当一个请求是页面请求(比如网站的主页),而来源是搜索引擎的链接(例如百度的搜索结果),也会被当成疑似CSRF攻击。所以在判断的时候需要过滤掉页面请求情况,通常Header符合以下情况:

    Accept: text/html
    Method: GET

    但相应的,页面请求就暴露在了CSRF的攻击范围之中。如果你的网站中,在页面的GET请求中对当前用户做了什么操作的话,防范就失效了。

    例如,下面的页面请求:

    GET https://example.com/addComment?comment=XXX&dest=orderId

    注:这种严格来说并不一定存在CSRF攻击的风险,但仍然有很多网站经常把主文档GET请求挂上参数来实现产品功能,但是这样做对于自身来说是存在安全风险的。

    另外,前面说过,CSRF大多数情况下来自第三方域名,但并不能排除本域发起。如果攻击者有权限在本域发布评论(含链接、图片等,统称UGC),那么它可以直接在本域发起攻击,这种情况下同源策略无法达到防护的作用。

    综上所述:同源验证是一个相对简单的防范方法,能够防范绝大多数的CSRF攻击。但这并不是万无一失的,对于安全性要求较高,或者有较多用户输入内容的网站,我们就要对关键的接口做额外的防护措施。

    CSRF Token

    前面讲到CSRF的另一个特征是,攻击者无法直接窃取到用户的信息(Cookie,Header,网站内容等),仅仅是冒用Cookie中的信息。

    而CSRF攻击之所以能够成功,是因为服务器误把攻击者发送的请求当成了用户自己的请求。那么我们可以要求所有的用户请求都携带一个CSRF攻击者无法获取到的Token。服务器通过校验请求是否携带正确的Token,来把正常的请求和攻击的请求区分开,也可以防范CSRF的攻击。

    利用Cookie的SameSite属性

    可以看看MDN对此的解释:

    https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Set-Cookie/SameSite

    SameSite可以设置为三个值,StrictLaxNone

    更多编程相关知识,请访问:编程入门!!

    以上就是看看这些关于浏览器的面试题,你能答对几个?的详细内容,更多请关注php中文网其它相关文章!

    声明:本文转载于:掘金社区,如有侵犯,请联系admin@php.cn删除
    专题推荐:浏览器 面试题
    上一篇:jquery怎么修改节点的内容 下一篇:es6深度拷贝的几种实现方法是什么
    Web大前端开发直播班

    相关文章推荐

    • Angular8+面试题整理之:基础知识点解析• 【吐血整理】28个关于PHP核心技术的面试题,助力跳槽!• 37个常见Vue面试题,增强你的Vue知识储备!• 看看这些jQuery常见面试题,帮助你更好理解基础知识!• 分享2022年最新的28道PHP面试题(附答案)• 分享一道逻辑面试题,看看你能答对吗!

    全部评论我要评论

  • 取消发布评论发送
  • 1/1

    PHP中文网