【Step-By-Step】一周面试题深切剖析 / 周刊 03

关于【Step-By-Step】

Step-By-Step (点击进入项目) 是我于
2019-05-20 最先的一个项目,每一个工作日宣布一道面试题。

每一个周末我会仔细浏览人人的答案,整顿最一份较优答案出来,因本人程度有限,有误的处所,人人实时斧正。

假如想 加群 进修,关注民众号,增添我为挚友,我拉你进群。

本周面试题一览:

  • 什么是XSS进击,XSS 进击可以分为哪几类?我们怎样提防XSS进击?
  • 怎样隐蔽页面中的某个元素?
  • 浏览器事宜代办机制的道理是什么?
  • setTimeout 倒计时为何会涌现偏差?

11. 什么是XSS进击,XSS进击可以分为哪几类?我们怎样提防XSS进击?

1. XSS进击

XSS(Cross-Site Scripting,跨站剧本进击)是一种代码注入进击。进击者在目的网站上注入歹意代码,当被进击者上岸网站时就会实行这些歹意代码,这些剧本可以读取 cookie,session tokens,或许别的敏感的网站信息,对用户举行垂纶敲诈,以至提议蠕虫进击等。

XSS 的实质是:歹意代码未经过滤,与网站一般的代码混在一同;浏览器没法区分哪些剧本是可托的,致使歹意剧本被实行。由于直接在用户的终端实行,歹意代码可以直接猎取用户的信息,应用这些信息假装用户向网站提议进击者定义的要求。

XSS分类

依据进击的泉源,XSS进击可以分为存储型(耐久性)、反射型(非耐久型)和DOM型三种。下面我们来细致相识一下这三种XSS进击:

1.1 反射型XSS

当用户点击一个歹意链接,或许提交一个表单,或许进入一个歹意网站时,注入剧本进入被进击者的网站。Web服务器将注入剧本,比方一个错误信息,搜刮结果等,未举行过滤直接返回到用户的浏览器上。

反射型 XSS 的进击步骤:

  1. 进击者组织出迥殊的 URL,个中包括歹意代码。
  2. 用户翻开带有歹意代码的 URL 时,网站服务端将歹意代码从 URL 中掏出,拼接在 HTML 中返回给浏览器。
  3. 用户浏览器接收到相应后剖析实行,混在个中的歹意代码也被实行。
  4. 歹意代码盗取用户数据并发送到进击者的网站,或许假装用户的行动,挪用目的网站接口实行进击者指定的操纵。

反射型 XSS 破绽常见于经由过程 URL 通报参数的功用,如网站搜刮、跳转等。由于须要用户主动翻开歹意的 URL 才见效,进击者往往会连系多种手腕引诱用户点击。

POST 的内容也可以触发反射型 XSS,只不过其触发前提比较刻薄(须要组织表单提交页面,并指导用户点击),所以异常少见。

假如不愿望被前端拿到cookie,后端可以设置 httpOnly (不过这不是 XSS进击 的解决方案,只能下落受损局限)

怎样提防反射型XSS进击

对字符串举行编码。

对url的查询参数举行转义后再输出到页面。

app.get('/welcome', function(req, res) {
    //对查询参数举行编码,防备反射型 XSS进击
    res.send(`${encodeURIComponent(req.query.type)}`); 
});

1.2 DOM 型 XSS

DOM 型 XSS 进击,实际上就是前端 JavaScript 代码不够严谨,把不可托的内容插进去到了页面。在运用 .innerHTML.outerHTML.appendChilddocument.write()等API时要迥殊警惕,不要把不可托的数据作为 HTML 插到页面上,只管运用 .innerText.textContent.setAttribute() 等。

DOM 型 XSS 的进击步骤:

  1. 进击者组织出迥殊数据,个中包括歹意代码。
  2. 用户浏览器实行了歹意代码。
  3. 歹意代码盗取用户数据并发送到进击者的网站,或许假装用户的行动,挪用目的网站接口实行进击者指定的操纵。

怎样提防 DOM 型 XSS 进击

提防 DOM 型 XSS 进击的中心就是对输入内容举行转义(DOM 中的内联事宜监听器和链接跳转都能把字符串作为代码运转,须要对其内容举行检查)。

1.关于url链接(比方图片的src属性),那末直接运用 encodeURIComponent 来转义。

2.非url,我们可以如许举行编码:

function encodeHtml(str) {
    return str.replace(/"/g, '"')
            .replace(/'/g, ''')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;');
}

DOM 型 XSS 进击中,掏出和实行歹意代码由浏览器端完成,属于前端 JavaScript 本身的安全破绽。

1.3 存储型XSS

歹意剧本永久存储在目的服务器上。当浏览器要求数据时,剧本从服务器传回并实行,影响局限比反射型和DOM型XSS更大。存储型XSS进击的缘由依然是没有做好数据过滤:前端提交数据至服务端时,没有做好过滤;服务端在接收到数据时,在存储之前,没有做过滤;前端从服务端要求到数据,没有过滤输出。

存储型 XSS 的进击步骤:

  1. 进击者将歹意代码提交到目的网站的数据库中。
  2. 用户翻开目的网站时,网站服务端将歹意代码从数据库掏出,拼接在 HTML 中返回给浏览器。
  3. 用户浏览器接收到相应后剖析实行,混在个中的歹意代码也被实行。
  4. 歹意代码盗取用户数据并发送到进击者的网站,或许假装用户的行动,挪用目的网站接口实行进击者指定的操纵。

这类进击常见于带有用户保留数据的网站功用,如论坛发帖、商品批评、用户私信等。

怎样提防存储型XSS进击:

  1. 前端数据通报给服务器之前,先转义/过滤(提防不了抓包修改数据的状况)
  2. 服务器接收到数据,在存储到数据库之前,举行转义/过滤
  3. 前端接收到服务器通报过来的数据,在展现到页眼前,先举行转义/过滤

除了郑重的转义,我们还须要其他一些手腕来提防XSS进击:

1.Content Security Policy

在服务端运用 HTTP的 Content-Security-Policy 头部来指定战略,或许在前端设置 meta 标签。

比方下面的设置只许可加载同域下的资本:

Content-Security-Policy: default-src 'self'
<meta http-equiv="Content-Security-Policy" content="form-action 'self';">

前端和服务端设置 CSP 的结果雷同,然则meta没法运用report

严厉的 CSP 在 XSS 的提防中可以起到以下的作用:

  1. 制止加载外域代码,防备庞杂的进击逻辑。
  2. 制止外域提交,网站被进击后,用户的数据不会泄漏到外域。
  3. 制止内联剧本实行(划定规矩较严厉,现在发明 GitHub 运用)。
  4. 制止未受权的剧本实行(新特征,Google Map 挪动版在运用)。
  5. 合理运用上报可以实时发明 XSS,利于尽快修复题目。

2.输入内容长度掌握

关于不受信托的输入,都应当限定一个合理的长度。虽然没法完整防备 XSS 发作,但可以增添 XSS 进击的难度。

3.输入内容限定

关于部份输入,可以限定不能包括迥殊字符或许仅能输入数字等。

4.其他安全措施

  • HTTP-only Cookie: 制止 JavaScript 读取某些敏感 Cookie,进击者完成 XSS 注入后也没法盗取此 Cookie。
  • 验证码:防备剧本假装用户提交风险操纵。

点击检察更多

12.怎样隐蔽页面中的某个元素?

隐蔽范例

屏幕并非唯一的输出机制,比方说屏幕上看不见的元素(隐蔽的元素),个中一些依旧可以被读屏软件浏览出来(由于读屏软件依赖于可接见性树来论述)。为了消弭它们之间的歧义,我们将其归为三大类:

  • 完整隐蔽:元素从衬着树中消逝,不占有空间。
  • 视觉上的隐蔽:屏幕中不可见,占有空间。
  • 语义上的隐蔽:读屏软件不可读,但一般占有空。

完整隐蔽

1.display 属性(不占有空间)
display: none;
2.hidden 属性 (不占有空间)

HTML5 新增属性,相当于 display: none

<div hidden>
</div>

视觉上的隐蔽

1.应用 position 和 盒模子 将元素移出可视区局限
  1. 设置 posoitionabsolutefixed,经由过程设置 topleft 等值,将其移出可视地区。(可视地区不占位)
position:absolute;
left: -99999px;
  1. 设置 positionrelative,经由过程设置 topleft 等值,将其移出可视地区。(可视地区占位)
position: relative;
left: -99999px;

如愿望其在可视地区不占位置,需同时设置 height: 0;

  1. 设置 margin 值,将其移出可视地区局限(可视地区占位)。
margin-left: -99999px;

假如愿望其在可视地区不占位,需同时设置 height: 0;

2.应用 transfrom
  1. 缩放(占有空间)
transform: scale(0);

假如愿望不占有空间,需同时设置 height: 0

  1. 挪动 translateX, translateY(占有空间)
transform: translateX(-99999px);

假如愿望不占有空间,需同时设置 height: 0

  1. 扭转 rotate (占有空间)
transform: rotateY(90deg);
3.设置其大小为0

宽高为0,字体大小为0:

height: 0;
width: 0;
font-size: 0;

宽高为0,超越隐蔽:

height: 0;
width: 0;
overflow: hidden;
4.设置透明度为0 (占有空间)
opacity: 0;
5.visibility属性 (占有空间)
visibility: hidden
6.层级掩盖,z-index 属性 (占有空间)
position: relative;
z-index: -999;

再设置一个层级较高的元素掩盖在此元素上。

7.clip-path 裁剪 (占有空间)
clip-path: polygon(0 0, 0 0, 0 0, 0 0);

语义上的隐蔽

aria-hidden 属性 (占有空间)

读屏软件不可读,占有空间,可见。

<div aria-hidden="true">
</div>

11. 运用JS将元素从页面中移除

点击检察更多

13.浏览器事宜代办机制的道理是什么?

事宜流

在说浏览器事宜代办机制道理之前,我们起首相识一下事宜流的观点,初期浏览器,IE采纳的是事宜捕捉事宜流,而Netscape采纳的则是事宜冒泡。”DOM2级事宜”把事宜流分为三个阶段,捕捉阶段、目的阶段、冒泡阶段。当代浏览器也都遵照此范例。

《【Step-By-Step】一周面试题深切剖析 / 周刊 03》

事宜代办机制的道理

事宜代办又称为事宜托付,在先人级 DOM 元素绑定一个事宜,当触发子孙级DOM元素的事宜时,应用事宜冒泡的道理来触发绑定在先人级 DOM 的事宜。由于事宜会从目的元素一层层冒泡至 document 对象。

为何要事宜代办?

  1. 增添到页面上的事宜数目会影响页面的运转机能,假如增添的事宜过量,会致使网页的机能下落。采纳事宜代办的体式格局,可以大大削减注册事宜的个数。
  2. 事宜代办的当时,某个子孙元素是动态增添的,不须要再次对其举行事宜绑定。
  3. 不必忧郁某个注册了事宜的DOM元素被移除后,能够没法接纳其事宜处置惩罚顺序,我们只要把事宜处置惩罚顺序托付给更高层级的元素,就可以防备此题目。
  4. 许可给一个事宜注册多个监听。
  5. 供应了一种更邃密的手腕掌握 listener 的触发阶段(可以挑选捕捉或许是冒泡)。
  6. 对任何 DOM 元素都是有用的,而不仅仅是对 HTML 元素有用。

addEventListener

addEventListener 接收3个参数,分别是要处置惩罚的事宜名、完成了 EventListener 接口的对象或许是一个函数、一个对象/一个布尔值。

target.addEventListener(type, listener[, options]);
target.addEventListener(type, listener[, useCapture]);

options(对象) | 可选

  • capture: Boolean。true 示意在捕捉阶段触发,false示意在冒泡阶段触发。默许是 false。
  • once:Boolean。true 示意listener 在增添以后最多只挪用一次,listener 会在其被挪用以后自动移除。默许是 false。
  • passive: Boolean。true 示意 listener 永久不会挪用 preventDefault()。假如 listener 依然挪用了这个函数,客户端将会疏忽它并抛出一个掌握台正告。默许是 false。

useCapture(Boolean) | 可选

useCapture 默许为 false。示意冒泡阶段挪用事宜处置惩罚顺序,若设置为 true,示意在捕捉阶段挪用事宜处置惩罚顺序。

如将页面中的一切click事宜都代办到document上:

document.addEventListener('click', function (e) {
    console.log(e.target);
    /**
    * 捕捉阶段挪用挪用事宜处置惩罚顺序,eventPhase是 1; 
    * 处于目的,eventPhase是2 
    * 冒泡阶段挪用事宜处置惩罚顺序,eventPhase是 3;
    */ 
    console.log(e.eventPhase);
    
}, false);

addEventListener 相对应的是 removeEventListener,用于移除事宜监听。

点击检察更多

14. setTimeout 倒计时为何会涌现偏差?

setTimeout 只能保证延时或距离不小于设定的时候。由于它实际上只是将回调增添到了宏使命行列中,然则假如主线程上有使命还没有实行完成,它必需要守候。

假如你对前面这句话不是异常明白,那末有必要相识一下 JS的运转机制。

JS的运转机制

(1)一切同步使命都在主线程上实行,构成一个实行栈(execution context stack)。

(2)主线程以外,还存在”使命行列”(task queue)。

(3)一旦”实行栈”中的一切同步使命实行终了,体系就会读取”使命行列”,看看内里有哪些事宜。那些对应的异步使命,因而完毕守候状况,进入实行栈,最先实行。

(4)主线程不停反复上面的第三步。

setTimeout(()=>{callback();}, 1000) ,即示意在1s以后将 callback 放到宏使命行列中,当1s的时候抵达时,假如主线程上有别的使命在实行,那末 callback 就必需要守候,别的 callback 的实行也须要时候,因而 setTimeout 的时候距离是有偏差的,它只能保证延时不小于设置的时候。

怎样削减 setTimeout 的偏差

我们只能削减实行屡次的 setTimeout 的偏差,比方倒计时功用。

倒计时的时候一般都是从服务端猎取的。形成偏差的缘由:

1.没有斟酌偏差时候(函数实行的时候/别的代码的壅塞)

2.没有斟酌浏览器的“休眠”

完整消弭 setTimeout的偏差是不能够的,然则我们削减 setTimeout 的偏差。经由过程对下一次使命的挪用时候举行修改,来削减偏差。

let count = 0;
let countdown = 5000; //服务器返回的倒计时时候
let interval = 1000;
let startTime = new Date().getTime();
let timer = setTimeout(countDownStart, interval); //初次实行
//定时器测试
function countDownStart() {
    count++;
    const offset = new Date().getTime() - (startTime + count * 1000);
    const nextInterval = interval - offset; //修改后的延时时候
    if (nextInterval < 0) {
        nextInterval = 0;
    }
    countdown -= interval;
    console.log("偏差:" + offset + "ms,下一次实行:" + nextInterval + "ms后,离运动最先另有:" + countdown + "ms");
    if (countdown <= 0) {
        clearTimeout(timer);
    } else {
        timer = setTimeout(countDownStart, nextInterval);
    }
}

假如当前页面是不可见的,那末倒计时会涌现大于100ms的偏差时候。因而在页面显现时,应当从新从服务端猎取剩余时候举行倒计时。固然,为了更好的机能,当倒计时不可见(Tab页切换/倒计时内容不在可视区时),可以挑选住手倒计时。

为此,我们可以监听 visibityChange 事宜举行处置惩罚。

点击检察更多

参考文章:

[1] MDN addEventListener

[2] https://www.ecma-internationa…

[3] http://www.xuanfengge.com/js-…

感谢列位小伙伴情愿消费珍贵的时候浏览本文,假如本文给了您一点协助或许是启示,请不要悭吝你的赞和Star,您的肯定是我行进的最大动力。https://github.com/YvetteLau/…

关注民众号,到场技术交流群。

《【Step-By-Step】一周面试题深切剖析 / 周刊 03》

    原文作者:刘小夕
    原文地址: https://segmentfault.com/a/1190000019429273
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞