澳门新浦京娱乐场网站-www.146.net-新浦京娱乐场官网
做最好的网站

澳门新浦京娱乐场网站:前端安全,二零一六A

JavaScript 防 http 劫持与 XSS

2016/08/17 · JavaScript · 1 评论 · http劫持, X DNS劫持, XSS, 安全

正文我: 伯乐在线 - chokcoco 。未经我许可,幸免转发!
接待插手伯乐在线 专辑小编。

用作前端,长期以来都驾驭HTTP劫持XSS跨站脚本(Cross-site scripting)、CSRF跨站请求伪造(Cross-site request forgery)。可是一贯都未有浓郁钻研过,上个月同事的分享会一时谈起,小编也对那豆蔻梢头块很感兴趣,便深切钻研了生机勃勃番。

多年来用 JavaScript 写了三个组件,能够在前面贰个层面预防部分 HTTP 压制与 XSS。

当然,防备那些威迫最棒的主意照旧从后端入手,前端能做的实在太少。况兼由于源码的展露,攻击者相当的轻便绕过大家的防范手腕。但是那不代表大家去探听那块的连带文化是没意义的,本文的累累艺术,用在其余地点也是大有功能。

已上传出 Github – httphijack.js ,接待感兴趣看看顺手点个 star ,本文示例代码,堤防方法在组件源码中皆可找到。

接下去步入正文。

用作前端,长久以来都驾驭HTTP劫持XSS跨站脚本(Cross-site scripting)、CSRF跨站请求伪造(Cross-site request forgery)。可是一向都不曾深入钻研过,前三个月同事的分享会一时谈到,小编也对那活龙活现块很感兴趣,便深远钻研了生机勃勃番。

1、JavaScript有哪些方法能消除跨主域难题?

一、概述

HTTP劫持、DNS劫持与XSS

先简单讲讲怎么着是 HTTP 威吓与 DNS 压迫。

前段时间用 JavaScript 写了一个零部件,可以在前面三个层面防备部分 HTTP 威吓与 XSS。

a. document.domain iframe的设置
b. 动态创造script
c. 利用iframe和location.hash
d. window.name达成的跨域数据传输
e. 使用HTML5 postMessage

f. 利用flash

attribute和property是时常被弄混的三个概念。

HTTP劫持

什么样是HTTP要挟呢,大大多情景是营业商HTTP威吓,当我们利用HTTP央浼供给贰个网址页面包车型大巴时候,互连网运行商会在正规的数目流中插入专心设计的网络数据报文,让客户端(经常是浏览器)呈现“错误”的数额,平日是部分弹窗,宣传性广告还是直接展示某网址的源委,大家应该都有蒙受过。

自然,防备那个威吓最佳的办法恐怕从后端入手,前端能做的实在太少。并且由于源码的展露,攻击者比较轻巧绕过大家的防止手段。可是那不代表大家去探听那块的有关文化是没意义的,本文的过多主意,用在任什么地区方也是大有功能。

JavaScript跨域:处于安全地点的思考,不容许跨域调用别的页面包车型客车靶子。一言以蔽之,由于JavaScript同源攻略的范围,a.com域名下的js不可能操作b.com或c.a.com域名下的目标。

简易的话,property则是JS代码里造访的:

DNS劫持

DNS胁制就是经过胁制了DNS服务器,通过一些手腕得到某域名的分析记录调节权,进而修改此域名的分析结果,导致对该域名的拜会由原IP地址转入到修改后的钦定IP,其结果就是对一定的网站不能访谈或访谈的是假网站,从而实现窃取资料还是损坏原有符合规律劳动的指标。

DNS 抑低就更过分了,轻巧说正是我们呼吁的是  ,直接被重定向了 ,本文不会过多商讨这种景况。

已上传播 Github – httphijack.js ,接待感兴趣看看顺手点个 star ,本文示例代码,防备措施在组件源码中皆可找到。

详见:  

document.getElementByTagName('my-element').prop1 = 'hello';

XSS跨站脚本

XSS指的是攻击者漏洞,向 Web 页面中注入恶意代码,当客商浏览该页之时,注入的代码会被试行,进而到达攻击的新鲜目标。

至于那么些攻击如何变化,攻击者怎么着注入恶意代码到页面中本文不做研讨,只要知道如 HTTP 威迫 和 XSS 最后都以恶意代码在客户端,日常也正是客商浏览器端施行,本文将商讨的正是假诺注入已经存在,怎么样利用 Javascript 进行有效的前端防护。

接下去步向正文。

2、以下关于Nodejs的说教, 准确的是(ACD)

attribute类似这种:

页面被安置 iframe 中,重定向 iframe

先来讲说大家的页面被平放了 iframe 的状态。也正是,互连网运维商为了尽或然地减小植入广告对本来网址页面的影响,平常会经过把原本网址页面放置到二个和原页面一样大小的 iframe 里面去,那么就足以因此这一个 iframe 来隔开广告代码对原始页面包车型地铁熏陶。
澳门新浦京娱乐场网站 1

这种场所还相比较好管理,大家只供给了然大家的页面是不是被嵌套在 iframe 中,假使是,则重定向外层页面到大家的通常页面就能够。

那正是说有没办法知情大家的页面当前留存于 iframe 中呢?有的,正是 window.self 与 window.top 。

 

A: Nodejs是一个Javascript运营境况, 基于chrome V8引擎进行代码剖判

B: Nodejs本人不是单线程的, 但我们的js代码是在单线程的条件中实践

C: 能够使用uncaughtException可能Domain捕获万分, 个中uncaughtException能够保证上下文

D: Nodejs高并发性情使其相符I/O密集型的施用

<my-element attr1="cool" />

window.self

回到八个针对性当前 window 对象的援用。

HTTP劫持、DNS劫持与XSS

先轻便讲讲什么是 HTTP 勒迫与 DNS 威吓。

 

JS代码里拜会attribute的不二等秘书技是getAttribute和setAttribute:

window.top

回到窗口连串中的最顶层窗口的征引。

对于非同源的域名,iframe 子页面不或然透过 parent.location 只怕top.location 获得现实的页面地址,可是能够写入 top.location ,也便是足以决定父页面包车型大巴跳转。

多个天性分别能够又简写为 self 与 top,所以当开掘我们的页面被嵌套在 iframe 时,能够重定向父级页面:

JavaScript

if (self != top) { // 大家的正规页面 var url = location.href; // 父级页面重定向 top.location = url; }

1
2
3
4
5
6
if (self != top) {
  // 我们的正常页面
  var url = location.href;
  // 父级页面重定向
  top.location = url;
}

 

HTTP劫持

什么样是HTTP抑遏呢,大好多处境是营业商HTTP威迫,当我们接纳HTTP诉求央求多个网址页面包车型客车时候,互联网运维商会在健康的数额流中插入专心设计的网络数据报文,让客商端(平时是浏览器)浮现“错误”的多寡,常常是有的弹窗,宣传性广告依旧直接显示某网址的内容,大家应该都有相逢过。

3、关于HTTP重回码的传教,下边哪些是不当的?(AB)

document.getElementByTagName('my-element').setAttribute('attr1','Hello');

选择白名单放行寻常 iframe 嵌套

当然相当多时候,大概运维要求,我们的页面会被以各个方法加大,也可能有极大可能率是平常职业供给被嵌套在 iframe 中,那一年大家要求二个白名单或许黑名单,当大家的页面被嵌套在 iframe 中且父级页面域名存在白名单中,则不做重定向操作。

上边也说了,使用 top.location.href 是没办法得到父级页面包车型地铁 UENVISIONL 的,那时候,需求动用document.referrer

透过 document.referrer 可以得到跨域 iframe 父页面包车型地铁UGL450L。

JavaScript

// 创设白名单 var whiteList = [ 'www.aaa.com', 'res.bbb.com' ]; if (self != top) { var // 使用 document.referrer 能够得到跨域 iframe 父页面包车型客车 U奥迪Q7L parentUrl = document.referrer, length = whiteList.length, i = 0; for(; i<length; i ){ // 创建白名单正则 var reg = new RegExp(whiteList[i],'i'); // 存在白名单中,放行 if(reg.test(parentUrl)){ return; } } // 我们的正规页面 var url = location.href; // 父级页面重定向 top.location = url; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 建立白名单
var whiteList = [
  'www.aaa.com',
  'res.bbb.com'
];
if (self != top) {
  var
    // 使用 document.referrer 可以拿到跨域 iframe 父页面的 URL
    parentUrl = document.referrer,
    length = whiteList.length,
    i = 0;
  for(; i<length; i ){
    // 建立白名单正则
    var reg = new RegExp(whiteList[i],'i');
    // 存在白名单中,放行
    if(reg.test(parentUrl)){
      return;
    }
  }
  // 我们的正常页面
  var url = location.href;
  // 父级页面重定向
  top.location = url;
}

 

DNS劫持

DNS 勒迫就是通过仰制了 DNS 服务器,通过某个花招获得某域名的解析记录调控权,进而修改此域名的剖释结果,导致对该域名的拜见由原IP地址转入到修改后的钦定IP,其结果正是对一定的网站无法访问或访谈的是假网址,进而达成窃取资料照旧损坏原有符合规律劳动的目标。

DNS 压迫比之 HTTP 仰制特别过分,简单说正是我们央浼的是  ,直接被重定向了 ,本文不会过多斟酌这种景况。

A: 302意味着服务器端网页未修改过,客商端可从浏览器缓存中拿走内容

B: 404代表能源固然存在,但运维出错

C: 503为服务器负荷过高不可能响应央浼

D: 传送数据过大恐怕形成413(诉求实体过大)的妄诞

document.getElementByTagName('my-element').getAttribute('attr1','Hello');

更换 UCR-VL 参数绕过运维商标志

如此就完了呢?未有,大家尽管重定向了父页面,可是在重定向的经过中,既然第二遍能够嵌套,那么那三回重定向的长河中页面大概又被 iframe 嵌套了,真尼玛蛋疼。

自然运行商这种威迫平日也可能有迹可循,最健康的花招是在页面 U哈弗L 中装置二个参数,比如  ,其中 iframe_hijack_redirected=1 表示页面已经被勒迫过了,就不再嵌套 iframe 了。所以依据那几个特点,大家得以改写大家的 UENVISIONL ,使之看上去已经被威吓了:

JavaScript

var flag = 'iframe_hijack_redirected'; // 当前页面存在于一个 iframe 中 // 此处要求创立三个白名单相配法则,白名单暗许放行 if (self != top) { var // 使用 document.referrer 能够获得跨域 iframe 父页面包车型客车 UPAJEROL parentUrl = document.referrer, length = whiteList.length, i = 0; for(; i<length; i ){ // 建构白名单正则 var reg = new RegExp(whiteList[i],'i'); // 存在白名单中,放行 if(reg.test(parentUrl)){ return; } } var url = location.href; var parts = url.split('#'); if (location.search) { parts[0] = '&' flag '=1'; } else { parts[0] = '?' flag '=1'; } try { console.log('页面被安置iframe中:', url); top.location.href = parts.join('#'); } catch (e) {} }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
var flag = 'iframe_hijack_redirected';
// 当前页面存在于一个 iframe 中
// 此处需要建立一个白名单匹配规则,白名单默认放行
if (self != top) {
  var
    // 使用 document.referrer 可以拿到跨域 iframe 父页面的 URL
    parentUrl = document.referrer,
    length = whiteList.length,
    i = 0;
  for(; i<length; i ){
    // 建立白名单正则
    var reg = new RegExp(whiteList[i],'i');
    // 存在白名单中,放行
    if(reg.test(parentUrl)){
      return;
    }
  }
  var url = location.href;
  var parts = url.split('#');
  if (location.search) {
    parts[0] = '&' flag '=1';
  } else {
    parts[0] = '?' flag '=1';
  }
  try {
    console.log('页面被嵌入iframe中:', url);
    top.location.href = parts.join('#');
  } catch (e) {}
}

理所必然,假若那几个参数一改,防嵌套的代码就失效了。所以大家还亟需树立三个举报系统,当发掘页面被嵌套时,发送贰个阻挠上报,尽管重定向失利,也足以领略页面嵌入 iframe 中的 U昂科威L,依照深入分析那一个 UENVISIONL ,不断增高大家的警务器具花招,这些后文少禽聊起。

XSS跨站脚本

XSS指的是攻击者利用漏洞,向 Web 页面中注入恶意代码,当顾客浏览该页之时,注入的代码会被实施,进而完成攻击的例外指标。

至于那一个攻击怎么着变化,攻击者怎么着注入恶意代码到页面中本文不做探讨,只要明白如 HTTP 威胁 和 XSS 最终都以恶意代码在客商端,常常约等于客户浏览器端实践,本文将研讨的正是假使注入已经存在,如何选拔Javascript 实行中用的前端防护。

 

二、区别

内联事件及内联脚本拦截

在 XSS 中,其实能够注入脚本的法子要命的多,特别是 HTML5 出来今后,一不细心,繁多的新标签都得以用来注入可实践脚本。

列出部分相比宽泛的注入格局:

  1. <a href="javascript:alert(1)" ></a>
  2. <iframe src="javascript:alert(1)" />
  3. <img src='x' onerror="alert(1)" />
  4. <video src='x' onerror="alert(1)" ></video>
  5. <div onclick="alert(1)" onmouseover="alert(2)" ><div>

除了一些未列出来的老大少见生僻的流入情势,当先55%都以 javascript:... 及内联事件 on*

小编们假如注入已经发生,那么有未有法子堵住这个内联事件与内联脚本的履好吗?

对此地点列出的 (1) (5) ,这种供给客商点击可能推行某种事件随后才施行的脚本,大家是有办法开展防备的。

 

4.1 说说nodejs的异步I/O是什么。

大多气象下,两个是平等的。在web标准中,平时会规定某attribute“反射”了同名的property。可是不一样的情况或许广大的。

浏览器事件模型

此处说能够堵住,涉及到了事件模型连带的规律。

大家都晓得,规范浏览器事件模型存在多个品级:

  • 抓获阶段
  • 对象阶段
  • 冒泡阶段

对于二个这么 <a href="javascript:alert(222)" ></a> 的 a 标签来讲,真正触发成分 alert(222) 是处于点击事件的对象阶段。

See the Pen EyrjkG by Chokcoco (@Chokcoco) on CodePen.

点击上边包车型客车 click me ,先弹出 111 ,后弹出 222。

那正是说,大家只必要在点击事件模型的抓获阶段对标签内 javascript:... 的源委创立首要字黑名单,实行过滤核查,就能够做到我们想要的阻拦效果。

对于 on* 类内联事件也是同理,只是对于那类事件太多,大家不可能手动枚举,能够运用代码自动枚举,完成对内联事件及内联脚本的阻拦。

以阻挡 a 标签内的 href="javascript:... 为例,大家得以这么写:

JavaScript

// 构建主要词黑名单 var keyword布莱克List = [ 'xss', 'BAIDU_SSP__wrapper', 'BAIDU_DSPUI_FLOWBAR' ]; document.add伊夫ntListener('click', function(e) { var code = ""; // 扫描 <a href="javascript:"> 的剧本 if (elem.tagName == 'A' && elem.protocol == 'javascript:') { var code = elem.href.substr(11); if (blackListMatch(keywordBlackList, code)) { // 注销代码 elem.href = 'javascript:void(0)'; console.log('拦截疑心事件:' code); } } }, true); /** * [黑名单相配] * @param {[Array]} blackList [黑名单] * @param {[String]} value [亟需申明的字符串] * @return {[Boolean]} [false -- 验证不经过,true -- 验证通过] */ function blackListMatch(blackList, value) { var length = blackList.length, i = 0; for (; i < length; i ) { // 创建黑名单正则 var reg = new RegExp(whiteList[i], 'i'); // 存在黑名单中,拦截 if (reg.test(value)) { return true; } } return false; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// 建立关键词黑名单
var keywordBlackList = [
  'xss',
  'BAIDU_SSP__wrapper',
  'BAIDU_DSPUI_FLOWBAR'
];
  
document.addEventListener('click', function(e) {
  var code = "";
  // 扫描 <a href="javascript:"> 的脚本
  if (elem.tagName == 'A' && elem.protocol == 'javascript:') {
    var code = elem.href.substr(11);
    if (blackListMatch(keywordBlackList, code)) {
      // 注销代码
      elem.href = 'javascript:void(0)';
      console.log('拦截可疑事件:' code);
    }
  }
}, true);
/**
* [黑名单匹配]
* @param  {[Array]} blackList [黑名单]
* @param  {[String]} value    [需要验证的字符串]
* @return {[Boolean]}         [false -- 验证不通过,true -- 验证通过]
*/
function blackListMatch(blackList, value) {
  var length = blackList.length,
    i = 0;
  for (; i < length; i ) {
    // 建立黑名单正则
    var reg = new RegExp(whiteList[i], 'i');
    // 存在黑名单中,拦截
    if (reg.test(value)) {
      return true;
    }
  }
  return false;
}

能够戳小编翻看DEMO。(张开页面后张开调节台查看 console.log)

点击图中那多少个按键,能够看到如下:

澳门新浦京娱乐场网站 2

这里大家用到了黑名单相称,下文还有大概会细说。

 

页面被安置 iframe 中,重定向 iframe

先来讲说我们的页面被平放了 iframe 的图景。也等于,网络运维商为了尽量地降低植入广告对原本网址页面包车型客车震慑,经常会通过把本来网址页面放置到三个和原页面同样大小的 iframe 里面去,那么就能够透过那一个 iframe 来隔开广告代码对本来页面的影响。
澳门新浦京娱乐场网站 3

这种景观还比较好管理,我们只须要知道大家的页面是还是不是被嵌套在 iframe 中,借使是,则重定向外层页面到大家的例行页面就能够。

那么有没法知情大家的页面当前存在于 iframe 中呢?有的,正是 window.self 与 window.top 。

4.2 面临纷纭的作业需求,多次回调的node代码场景,你有哪些观念?怎么着让代码越来越好读书和保险。

  1. 名字不相同样

静态脚本拦截

XSS 跨站脚本的精髓不在于“跨站”,在于“脚本”。

通常说来来说,攻击者可能运行商会向页面中注入三个<script>剧本,具体操作都在剧本中完成,这种威吓方式只必要注入贰回,有改换的话无需每趟都再一次注入。

大家只要今后页面上被注入了一个 <script src="http://attack.com/xss.js"> 脚本,我们的对象正是拦住那么些本子的推行。

听上去很辛劳啊,什么看头啊。正是在剧本试行前开掘这一个狐疑脚本,並且销毁它使之无法举办内部代码。

就此大家需求利用一些高档 API ,能够在页面加载时对转移的节点开展检查实验。

 

window.self

回来贰个针对当前 window 对象的引用。

 

最举世无双的是className,为了逃脱JavaScript保留字,JS中跟class attribute对应的property是className。

MutationObserver

MutationObserver 是 HTML5 新添的 API,功用很刚劲,给开拓者们提供了如火如荼种能在某些范围内的 DOM 树产生变化时作出确切反应的力量。

说的很微妙,大致的情趣正是可以监测到页面 DOM 树的改换,并作出反应。

MutationObserver() 该构造函数用来实例化三个新的Mutation观看者对象。

JavaScript

MutationObserver( function callback );

1
2
3
MutationObserver(
  function callback
);

目瞪狗呆,这一大段又是什么?意思便是 MutationObserver 在考查时不要发掘二个新因素就即刻回调,而是将二个时刻有些里冒出的持有因素,一齐传过来。所以在回调中我们须求实行批量拍卖。而且,当中的 callback 会在钦赐的 DOM 节点(目的节点)爆发变化时被调用。在调用时,观看者对象会传给该函数三个参数,第贰个参数是个包括了若干个 MutationRecord 对象的数组,第三个参数则是以此观察者对象自作者。

于是,使用 MutationObserver ,大家能够对页面加载的种种静态脚本文件,实行督察:

JavaScript

// MutationObserver 的两样包容性写法 var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver; // 该构造函数用来实例化一个新的 Mutation 观看者对象 // Mutation 观看者对象能监听在某些范围内的 DOM 树变化 var observer = new MutationObserver(function(mutations) { mutations.forEach(function(mutation) { // 再次回到被抬高的节点,只怕为null. var nodes = mutation.addedNodes; for (var i = 0; i < nodes.length; i ) { var node = nodes[i]; if (/xss/i.test(node.src))) { try { node.parentNode.removeChild(node); console.log('拦截疑惑静态脚本:', node.src); } catch (e) {} } } }); }); // 传入目标节点和考查选项 // 若是target 为 document 恐怕 document.documentElement // 则当前文书档案中持有的节点加多与删除操作都会被观望到 observer.observe(document, { subtree: true, childList: true });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// MutationObserver 的不同兼容性写法
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver ||
window.MozMutationObserver;
// 该构造函数用来实例化一个新的 Mutation 观察者对象
// Mutation 观察者对象能监听在某个范围内的 DOM 树变化
var observer = new MutationObserver(function(mutations) {
  mutations.forEach(function(mutation) {
    // 返回被添加的节点,或者为null.
    var nodes = mutation.addedNodes;
    for (var i = 0; i < nodes.length; i ) {
      var node = nodes[i];
      if (/xss/i.test(node.src))) {
        try {
          node.parentNode.removeChild(node);
          console.log('拦截可疑静态脚本:', node.src);
        } catch (e) {}
      }
    }
  });
});
// 传入目标节点和观察选项
// 如果 target 为 document 或者 document.documentElement
// 则当前文档中所有的节点添加与删除操作都会被观察到
observer.observe(document, {
  subtree: true,
  childList: true
});

能够见见如下:能够戳小编翻看DEMO。(展开页面后打开调控台查看 console.log)

澳门新浦京娱乐场网站 4

<script type="text/javascript" src="./xss/a.js"></script> 是页面加载一发端就存在的静态脚本(查看页面结构),大家选用MutationObserver 可以在剧本加载之后,实践以前那几个时刻段对其剧情做正则相称,开掘恶意代码则 removeChild() 掉,使之不恐怕奉行。

window.top

回来窗口类别中的最顶层窗口的援用。

对此非同源的域名,iframe 子页面不可能透过 parent.location 恐怕 top.location 得到现实的页面地址,但是足以写入 top.location ,也正是足以垄断(monopoly)父页面包车型地铁跳转。

两脾个性分别能够又简写为 self 与 top,所以当发掘我们的页面被嵌套在 iframe 时,可以重定向父级页面:

if (self != top) {
  // 我们的正常页面
  var url = location.href;
  // 父级页面重定向
  top.location = url;
}

  

5、你选择NodeJS编写了贰个博客程序并把它计划到了龙行虎步台linux服务器上,怎样保证服务安全平稳地可不断运作吧?(要求部分能够依据代码、命令等) 

<div class="cls1 cls2"></div>

运用白名单对 src 进行相配过滤

上边的代码中,大家看清叁个js脚本是不是是恶意的,用的是这一句:

JavaScript

if (/xss/i.test(node.src)) {}

1
if (/xss/i.test(node.src)) {}

自然实际此中,注入恶意代码者不会那么傻,把名字改成 XSS 。所以,大家很有必不可缺采纳白名单进行过滤和创设二个拦截上报系统。

JavaScript

// 创设白名单 var whiteList = [ 'www.aaa.com', 'res.bbb.com' ]; /** * [白名单相称] * @param {[Array]} whileList [白名单] * @param {[String]} value [亟需表达的字符串] * @return {[Boolean]} [false -- 验证不经过,true -- 验证通过] */ function whileListMatch(whileList, value) { var length = whileList.length, i = 0; for (; i < length; i ) { // 营造白名单正则 var reg = new RegExp(whiteList[i], 'i'); // 存在白名单中,放行 if (reg.test(value)) { return true; } } return false; } // 只放行白名单 if (!whileListMatch(blackList, node.src)) { node.parentNode.removeChild(node); }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// 建立白名单
var whiteList = [
  'www.aaa.com',
  'res.bbb.com'
];
/**
* [白名单匹配]
* @param  {[Array]} whileList [白名单]
* @param  {[String]} value    [需要验证的字符串]
* @return {[Boolean]}         [false -- 验证不通过,true -- 验证通过]
*/
function whileListMatch(whileList, value) {
  var length = whileList.length,
    i = 0;
  for (; i < length; i ) {
    // 建立白名单正则
    var reg = new RegExp(whiteList[i], 'i');
    // 存在白名单中,放行
    if (reg.test(value)) {
      return true;
    }
  }
  return false;
}
// 只放行白名单
if (!whileListMatch(blackList, node.src)) {
  node.parentNode.removeChild(node);
}

此地大家已经多次关联白名单相称了,下文还有大概会用到,所以能够这里把它归纳封装成五个主意调用。

行使白名单放行正常 iframe 嵌套

自然非常多时候,可能运维供给,大家的页面会被以各个方式扩充,也许有异常的大只怕是寻常工作供给被嵌套在 iframe 中,那年我们须求三个白名单或然黑名单,当大家的页面被嵌套在 iframe 中且父级页面域名存在白名单中,则不做重定向操作。

地点也说了,使用 top.location.href 是不能够获得父级页面包车型大巴 UWranglerL 的,那时候,须求利用document.referrer

由此document.referrer 能够得到跨域 iframe 父页面包车型客车U索罗德L。

// 建立白名单
var whiteList = [
  'www.aaa.com',
  'res.bbb.com'
];

if (self != top) {
  var
    // 使用 document.referrer 可以拿到跨域 iframe 父页面的 URL
    parentUrl = document.referrer,
    length = whiteList.length,
    i = 0;

  for(; i<length; i  ){
    // 建立白名单正则
    var reg = new RegExp(whiteList[i],'i');

    // 存在白名单中,放行
    if(reg.test(parentUrl)){
      return;
    }
  }

  // 我们的正常页面
  var url = location.href;
  // 父级页面重定向
  top.location = url;
}

 

 

<script>

动态脚本拦截

上边运用 MutationObserver 拦截静态脚本,除了静态脚本,与之相应的正是动态变化的脚本。

JavaScript

var script = document.createElement('script'); script.type = 'text/javascript'; script.src = ''; document.getElementsByTagName('body')[0].appendChild(script);

1
2
3
4
5
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = 'http://www.example.com/xss/b.js';
document.getElementsByTagName('body')[0].appendChild(script);

要阻止这类动态变化的脚本,且拦截机会要在它插入 DOM 树中,实施从前,本来是能够监听 Mutation Events 中的 DOMNodeInserted 事件的。

更动 UCR-VL 参数绕过运维商标识

像这种类型就完了啊?没有,我们尽管重定向了父页面,可是在重定向的进度中,既然第叁回能够嵌套,那么那一遍重定向的经过中页面只怕又被 iframe 嵌套了,真尼玛蛋疼。

本来运转商这种威胁常常也会有迹可循,最健康的花招是在页面 URAV4L 中设置一个参数,比如  ,其中 iframe_hijack_redirected=1 表示页面已经被勒迫过了,就不再嵌套 iframe 了。所以依靠这一个天性,我们能够改写我们的 U汉兰达L ,使之看上去已经被要挟了:

var flag = 'iframe_hijack_redirected';
// 当前页面存在于一个 iframe 中
// 此处需要建立一个白名单匹配规则,白名单默认放行
if (self != top) {
  var
    // 使用 document.referrer 可以拿到跨域 iframe 父页面的 URL
    parentUrl = document.referrer,
    length = whiteList.length,
    i = 0;

  for(; i<length; i  ){
    // 建立白名单正则
    var reg = new RegExp(whiteList[i],'i');

    // 存在白名单中,放行
    if(reg.test(parentUrl)){
      return;
    }
  }

  var url = location.href;
  var parts = url.split('#');
  if (location.search) {
    parts[0]  = '&'   flag   '=1';
  } else {
    parts[0]  = '?'   flag   '=1';
  }
  try {
    console.log('页面被嵌入iframe中:', url);
    top.location.href = parts.join('#');
  } catch (e) {}
}

道理当然是这样的,若是这一个参数一改,防嵌套的代码就失效了。所以大家还需求树立一个举报系统,当开掘页面被嵌套时,发送二个截留上报,固然重定向败北,也能够领略页面嵌入 iframe 中的 UOdysseyL,根据深入分析那么些 URL ,不断抓牢大家的警务道具手段,这些后文子禽聊起。

6、Taobao首页需求达成如此二个意义,对于页面上非taobao.com域名下的链接,在顾客点击时,须要在链接处弹出提示框,提醒顾客此链接非Tmall域名下的链接,并予以客商挑选是不是继续访谈。要是顾客确认继续拜会,则在新窗口展开链接。请写出相应的代码。 

var div = document.getElementByTagName('div');

 

澳门新浦京娱乐场网站 5澳门新浦京娱乐场网站 6

div.className //cls1 cls2

Mutation Events 与 DOMNodeInserted

打开 MDN ,第一句便是:

该性格已经从 Web 规范中剔除,固然有的浏览器如今依旧支撑它,但可能会在以往的某部时刻甘休帮助,请尽量不要使用该脾气。

固然如此不能够用,也得以明白一下:

JavaScript

document.addEventListener('DOMNodeInserted', function(e) { var node = e.target; if (/xss/i.test(node.src) || /xss/i.test(node.innerHTML)) { node.parentNode.removeChild(node); console.log('拦截疑忌动态脚本:', node); } }, true);

1
2
3
4
5
6
7
document.addEventListener('DOMNodeInserted', function(e) {
  var node = e.target;
  if (/xss/i.test(node.src) || /xss/i.test(node.innerHTML)) {
    node.parentNode.removeChild(node);
    console.log('拦截可疑动态脚本:', node);
  }
}, true);

然而缺憾的是,使用方面包车型客车代码拦截动态变化的剧本,能够阻止到,可是代码也施行了:DOMNodeInserted 看名称就能够想到其意义,能够监听有些DOM 范围内的构造变化,与 MutationObserver 比较,它的实行机遇更早。

澳门新浦京娱乐场网站 7

但是 DOMNodeInserted 不再建议采纳,所以监听动态脚本的职责也要交给 MutationObserver

可惜的是,在其实奉行进度中,使用 MutationObserver 的结果和 DOMNodeInserted 同样,能够监听拦截到动态脚本的变型,不过敬谢不敏在本子执行从前,使用 removeChild 将其移除,所以我们还亟需考虑其余方法。

内联事件及内联脚本拦截

在 XSS 中,其实能够注入脚本的章程相当多,特别是 HTML5 出来之后,一不留意,许多的新标签都得以用于注入可进行脚本。

列出有些比较宽泛的流入方式:

  1. <a href="javascript:alert(1)" ></a>
  2. <iframe src="javascript:alert(1)" />
  3. <img src='x' onerror="alert(1)" />
  4. <video src='x' onerror="alert(1)" ></video>
  5. <div onclick="alert(1)" onmouseover="alert(2)" ><div>

除此之外一些未列出来的丰硕少见生僻的注入格局,抢先61%都是 javascript:... 及内联事件 on*

咱俩只要注入已经产生,那么有没有方法拦截那么些内联事件与内联脚本的推行呢?

对于地点列出的 (1) (5) ,这种须求客商点击或然施行某种事件过后才实践的本子,大家是有方法进行防范的。

<!DOCTYPE html>
<html>

</scrpit>

重写 setAttribute 与 document.write

浏览器事件模型

这里说能够阻止,涉及到了事件模型连锁的法则。

大家都明白,规范浏览器事件模型存在七个级次:

  • 破获阶段
  • 对象阶段
  • 冒泡阶段

对此三个如此 <a href="javascript:alert(222)" ></a> 的 a 标签来说,真正触发成分 alert(222) 是处于点击事件的指标阶段。

点击上面包车型客车 click me ,先弹出 111 ,后弹出 222。

那正是说,大家只需求在点击事件模型的破获阶段对标签内 javascript:... 的剧情创立第一字黑名单,进行过滤调查,就能够达成大家想要的阻碍效果。

对于 on* 类内联事件也是同理,只是对于那类事件太多,我们不能够手动枚举,能够动用代码自动枚举,完毕对内联事件及内联脚本的遏止。

以堵住 a 标签内的 href="javascript:... 为例,我们得以那样写:

// 建立关键词黑名单
var keywordBlackList = [
  'xss',
  'BAIDU_SSP__wrapper',
  'BAIDU_DSPUI_FLOWBAR'
];

document.addEventListener('click', function(e) {
  var code = "";

  // 扫描 <a href="javascript:"> 的脚本
  if (elem.tagName == 'A' && elem.protocol == 'javascript:') {
    var code = elem.href.substr(11);

    if (blackListMatch(keywordBlackList, code)) {
      // 注销代码
      elem.href = 'javascript:void(0)';
      console.log('拦截可疑事件:'   code);
    }
  }
}, true);

/**
 * [黑名单匹配]
 * @param  {[Array]} blackList [黑名单]
 * @param  {[String]} value    [需要验证的字符串]
 * @return {[Boolean]}         [false -- 验证不通过,true -- 验证通过]
 */
function blackListMatch(blackList, value) {
  var length = blackList.length,
    i = 0;

  for (; i < length; i  ) {
    // 建立黑名单正则
    var reg = new RegExp(whiteList[i], 'i');

    // 存在黑名单中,拦截
    if (reg.test(value)) {
      return true;
    }
  }
  return false;
}

能够戳笔者查看DEMO。(张开页面后打开调整台查看 console.log) 

点击图中那多少个开关,能够见见如下:

澳门新浦京娱乐场网站 8

此地大家用到了黑名单相称,下文还有大概会细说。

 

<head>
    <meta charset="utf-8"></meta>
    <title></title>
</head>

  1. 花色不等同

重写原生 Element.prototype.setAttribute 方法

在动态脚本插入实施前,监听 DOM 树的扭转拦截它不行,脚本如故会奉行。

那正是说大家供给向上追寻,在剧本插入 DOM 树前的破获它,那正是创造脚本时那一个空子。

日新月异旦未来有一个动态脚本是那般创制的:

JavaScript

var script = document.createElement('script'); script.setAttribute('type', 'text/javascript'); script.setAttribute('src', ''); document.getElementsByTagName('body')[0].appendChild(script);

1
2
3
4
5
var script = document.createElement('script');
script.setAttribute('type', 'text/javascript');
script.setAttribute('src', 'http://www.example.com/xss/c.js');
document.getElementsByTagName('body')[0].appendChild(script);

而重写 Element.prototype.setAttribute 也是卓有功效的:大家开掘这里运用了 setAttribute 方法,假使大家能够改写这几个原生方法,监听设置 src 属性时的值,通过黑名单只怕白名单决断它,就能够剖断该标签的合法性了。

JavaScript

// 保存原有接口 var old_setAttribute = Element.prototype.setAttribute; // 重写 setAttribute 接口 Element.prototype.setAttribute = function(name, value) { // 相称到 <script src='xxx' > 类型 if (this.tagName == 'SC奥迪Q5IPT' && /^src$/i.test(name)) { // 白名单相称 if (!whileListMatch(whiteList, value)) { console.log('拦截质疑模块:', value); return; } } // 调用原始接口 old_setAttribute.apply(this, arguments); }; // 建构白名单 var whiteList = [ 'www.yy.com', 'res.cont.yy.com' ]; /** * [白名单相配] * @param {[Array]} whileList [白名单] * @param {[String]} value [急需验证的字符串] * @return {[Boolean]} [false -- 验证不经过,true -- 验证通过] */ function whileListMatch(whileList, value) { var length = whileList.length, i = 0; for (; i < length; i ) { // 创设白名单正则 var reg = new RegExp(whiteList[i], 'i'); // 存在白名单中,放行 if (reg.test(value)) { return true; } } return false; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// 保存原有接口
var old_setAttribute = Element.prototype.setAttribute;
// 重写 setAttribute 接口
Element.prototype.setAttribute = function(name, value) {
  // 匹配到 <script src='xxx' > 类型
  if (this.tagName == 'SCRIPT' && /^src$/i.test(name)) {
    // 白名单匹配
    if (!whileListMatch(whiteList, value)) {
      console.log('拦截可疑模块:', value);
      return;
    }
  }
  
  // 调用原始接口
  old_setAttribute.apply(this, arguments);
};
// 建立白名单
var whiteList = [
'www.yy.com',
'res.cont.yy.com'
];
/**
* [白名单匹配]
* @param  {[Array]} whileList [白名单]
* @param  {[String]} value    [需要验证的字符串]
* @return {[Boolean]}         [false -- 验证不通过,true -- 验证通过]
*/
function whileListMatch(whileList, value) {
  var length = whileList.length,
    i = 0;
  for (; i < length; i ) {
    // 建立白名单正则
    var reg = new RegExp(whiteList[i], 'i');
    // 存在白名单中,放行
    if (reg.test(value)) {
      return true;
    }
  }
  return false;
}

能够见到如下结果:能够戳作者查看DEMO。(展开页面后张开调控台查看 console.log)

澳门新浦京娱乐场网站 9

重写 Element.prototype.setAttribute ,就是率先保存原有接口,然后当有成分调用 setAttribute 时,检查传入的 src 是还是不是存在于白名单中,存在则放行,不设有则正是困惑成分,实行上报并不付与实行。最后对放行的因素试行原生的 setAttribute ,也就是 old_setAttribute.apply(this, arguments);

上述的白名单相称也得以换来黑名单相称。

静态脚本拦截

XSS 跨站脚本的经典不在于“跨站”,在于“脚本”。

平常来说,攻击者或然运转商会向页面中流入叁个<script>本子,具体操作都在剧本中贯彻,这种勒迫方式只要求注入贰遍,有改观的话没有供给每一回都再次注入。

大家只要以往页面上被注入了二个 <script src="http://attack.com/xss.js"> 脚本,大家的指标便是拦住那几个本子的施行。

听上去非常不便啊,什么看头呢。就是在剧本试行前开掘那一个狐疑脚本,何况销毁它使之不可能施行内部代码。

故此大家须求运用一些高端API ,能够在页面加载时对转移的节点开展检查测量检验。

 

<body>
    <a href=";
    <a href=";
    <a href=";
    <script type="text/javascript" src="link.js"></script>
</body>

最特异的是style,不收受字符串型赋值。

MutationObserver

MutationObserver 是 HTML5 新增添的 API,功效很有力,给开辟者们提供了生机勃勃种能在有些范围内的 DOM 树产生变化时作出确切反应的本领。

说的很神秘,大致的意趣正是力所能致监测到页面 DOM 树的调换,并作出反应。

MutationObserver() 该构造函数用来实例化三个新的Mutation观看者对象。

MutationObserver(
  function callback
);

目瞪狗呆,这一大段又是啥?意思正是MutationObserver 在观看时不用开采一个新因素就当下回调,而是将几个岁月部分里涌出的有所因素,一同传过来。所以在回调中大家必要开展批量甩卖。并且,在那之中的 callback 会在钦命的 DOM 节点(指标节点)产生变化时被调用。在调用时,观看者对象会传给该函数三个参数,第三个参数是个蕴涵了若干个 MutationRecord 对象的数组,第三个参数则是其意气风发观望者对象自小编。

故而,使用 MutationObserver ,咱们得以对页面加载的各类静态脚本文件,举办督察:

// MutationObserver 的不同兼容性写法
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || 
window.MozMutationObserver;
// 该构造函数用来实例化一个新的 Mutation 观察者对象
// Mutation 观察者对象能监听在某个范围内的 DOM 树变化
var observer = new MutationObserver(function(mutations) {
  mutations.forEach(function(mutation) {
    // 返回被添加的节点,或者为null.
    var nodes = mutation.addedNodes;

    for (var i = 0; i < nodes.length; i  ) {
      var node = nodes[i];
      if (/xss/i.test(node.src))) {
        try {
          node.parentNode.removeChild(node);
          console.log('拦截可疑静态脚本:', node.src);
        } catch (e) {}
      }
    }
  });
});

// 传入目标节点和观察选项
// 如果 target 为 document 或者 document.documentElement
// 则当前文档中所有的节点添加与删除操作都会被观察到
observer.observe(document, {
  subtree: true,
  childList: true
});

能够看见如下:能够戳笔者翻看DEMO。(张开页面后展开调控台查看 console.log)

澳门新浦京娱乐场网站 10

<script type="text/javascript" src="./xss/a.js"></script> 是页面加载轰轰烈烈上马就存在的静态脚本(查看页面结构),大家应用 MutationObserver 能够在剧本加载之后,推行早先那几个小时段对其剧情做正则相称,开采恶意代码则 removeChild() 掉,使之不大概推行。

</html>

<div class="cls1 cls2" style="color:blue" ></div>

重写嵌套 iframe 内的 Element.prototype.setAttribute

理所必然,上边的写法假若 old_setAttribute = Element.prototype.setAttribute 揭示给攻击者的话,间接采纳old_setAttribute 就能够绕过大家重写的法子了,所以这段代码必须包在贰个闭包内。

当然如此也不保证,即使前段时间窗口下的 Element.prototype.setAttribute 已经被重写了。不过依旧有手腕能够获得原生的 Element.prototype.setAttribute ,只必要贰个新的 iframe 。

JavaScript

var newIframe = document.createElement('iframe'); document.body.appendChild(newIframe); Element.prototype.setAttribute = newIframe.contentWindow.Element.prototype.setAttribute;

1
2
3
4
var newIframe = document.createElement('iframe');
document.body.appendChild(newIframe);
Element.prototype.setAttribute = newIframe.contentWindow.Element.prototype.setAttribute;

透过这么些办法,能够另行得到原生的 Element.prototype.setAttribute ,因为 iframe 内的景况和外围 window 是一丝一毫切断的。wtf?

澳门新浦京娱乐场网站 11

如何做?我们看出创立 iframe 用到了 createElement,那么是还是不是能够重写原生 createElement 呢?不过除却createElement 还有 createElementNS ,还应该有望是页面三月经存在 iframe,所以不安妥。

这就在每当新创立贰个新 iframe 时,对 setAttribute 进行保险重写,这里又有用到 MutationObserver :

JavaScript

/** * 使用 MutationObserver 对转移的 iframe 页面举行督察, * 制止调用内部原生 setAttribute 及 document.write * @return {[type]} [description]澳门新浦京娱乐场网站, */ function defenseIframe() { // 先爱抚当前页面 installHook(window); } /** * 实现单个 window 窗口的 setAttribute爱抚 * @param {[BOM]} window [浏览器window对象] * @return {[type]} [description] */ function installHook(window) { // 重写单个 window 窗口的 setAttribute 属性 resetSetAttribute(window); // MutationObserver 的分歧包容性写法 var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver; // 该构造函数用来实例化一个新的 Mutation 观看者对象 // Mutation 观看者对象能监听在某些范围内的 DOM 树变化 var observer = new MutationObserver(function(mutations) { mutations.forEach(function(mutation) { // 重返被加多的节点,或然为null. var nodes = mutation.addedNodes; // 每个遍历 for (var i = 0; i < nodes.length; i ) { var node = nodes[i]; // 给生成的 iframe 里遭受也装上海重机厂写的钩 if (node.tagName == 'IFRAME') { installHook(node.contentWindow); } } }); }); observer.observe(document, { subtree: true, childList: true }); } /** * 重写单个 window 窗口的 setAttribute 属性 * @param {[BOM]} window [浏览器window对象] * @return {[type]} [description] */ function resetSetAttribute(window) { // 保存原有接口 var old_setAttribute = window.Element.prototype.setAttribute; // 重写 setAttribute 接口 window.Element.prototype.setAttribute = function(name, value) { ... }; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
/**
* 使用 MutationObserver 对生成的 iframe 页面进行监控,
* 防止调用内部原生 setAttribute 及 document.write
* @return {[type]} [description]
*/
function defenseIframe() {
  // 先保护当前页面
  installHook(window);
}
/**
* 实现单个 window 窗口的 setAttribute保护
* @param  {[BOM]} window [浏览器window对象]
* @return {[type]}       [description]
*/
function installHook(window) {
  // 重写单个 window 窗口的 setAttribute 属性
  resetSetAttribute(window);
  // MutationObserver 的不同兼容性写法
  var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
  // 该构造函数用来实例化一个新的 Mutation 观察者对象
  // Mutation 观察者对象能监听在某个范围内的 DOM 树变化
  var observer = new MutationObserver(function(mutations) {
    mutations.forEach(function(mutation) {
      // 返回被添加的节点,或者为null.
      var nodes = mutation.addedNodes;
      // 逐个遍历
      for (var i = 0; i < nodes.length; i ) {
        var node = nodes[i];
        // 给生成的 iframe 里环境也装上重写的钩子
        if (node.tagName == 'IFRAME') {
          installHook(node.contentWindow);
        }
      }
    });
  });
  observer.observe(document, {
    subtree: true,
    childList: true
  });
}
/**
* 重写单个 window 窗口的 setAttribute 属性
* @param  {[BOM]} window [浏览器window对象]
* @return {[type]} [description]
*/
function resetSetAttribute(window) {
  // 保存原有接口
  var old_setAttribute = window.Element.prototype.setAttribute;
  // 重写 setAttribute 接口
  window.Element.prototype.setAttribute = function(name, value) {
    ...
  };
}

咱俩定义了一个 installHook 方法,参数是叁个 window ,在此个方法里,大家将重写传入的 window 下的 setAttribute ,并且安装多个 MutationObserver ,并对此窗口下以往或者创制的 iframe 实行监听,借使以后在那 window 下成立了一个iframe ,则对新的 iframe 也装上 installHook 方法,以此进行层层爱抚。

 

View HTML Code

<script>

应用白名单对 src 进行相称过滤

上面的代码中,大家看清一个js脚本是或不是是恶意的,用的是这一句:

if (/xss/i.test(node.src)) {}

自然实际在那之中,注入恶意代码者不会那么傻,把名字改成 XSS 。所以,大家很有至关重要选择白名单实行过滤和创建一个阻止上报系统。 

// 建立白名单
var whiteList = [
  'www.aaa.com',
  'res.bbb.com'
];

/**
 * [白名单匹配]
 * @param  {[Array]} whileList [白名单]
 * @param  {[String]} value    [需要验证的字符串]
 * @return {[Boolean]}         [false -- 验证不通过,true -- 验证通过]
 */
function whileListMatch(whileList, value) {
  var length = whileList.length,
    i = 0;

  for (; i < length; i  ) {
    // 建立白名单正则
    var reg = new RegExp(whiteList[i], 'i');

    // 存在白名单中,放行
    if (reg.test(value)) {
      return true;
    }
  }
  return false;
}

// 只放行白名单
if (!whileListMatch(blackList, node.src)) {
  node.parentNode.removeChild(node);
} 

那边大家已经三回九转提到白名单相称了,下文还有大概会用到,所以能够这里把它概括封装成贰个措施调用。

澳门新浦京娱乐场网站 12澳门新浦京娱乐场网站 13

var div = document.getElementByTagName('div');

重写 document.write

依照上述的法子,大家能够承接打通一下,还有啥样办法能够重写,以便对页面进行更加好的保卫安全。

document.write 是二个很正确选拔,注入攻击者,经常会采用这一个艺术,往页面上注入一些弹窗广告。

大家得以重写 document.write ,使用首要词黑名单对剧情张开相称。

什么样对比切合当黑名单的主要字呢?大家得以看看一些广告相当多的页面:

澳门新浦京娱乐场网站 14

此处在页面最尾部放置了贰个 iframe ,里面装了广告代码,这里的最外层的 id 名id="BAIDU_SSP__wrapper_u2444091_0" 就很切合成为我们判定是还是不是是恶意代码的贰个注解,假设我们早已依据拦截上报采撷到了一群黑名单列表:

JavaScript

// 创立正则拦截关键词 var keywordBlackList = [ 'xss', 'BAIDU_SSP__wrapper', 'BAIDU_DSPUI_FLOWBAR' ];

1
2
3
4
5
6
// 建立正则拦截关键词
var keywordBlackList = [
'xss',
'BAIDU_SSP__wrapper',
'BAIDU_DSPUI_FLOWBAR'
];

接下去大家只需求使用那个主要字,对 document.write 传入的内容举办正则推断,就可以分明是还是不是要阻止document.write 这段代码。

JavaScript

```javascript // 创设首要词黑名单 var keywordBlackList = [ 'xss', 'BAIDU_SSP__wrapper', 'BAIDU_DSPUI_FLOWBAR' ]; /** * 重写单个 window 窗口的 document.write 属性 * @param {[BOM]} window [浏览器window对象] * @return {[type]} [description] */ function resetDocumentWrite(window) { var old_write = window.document.write; window.document.write = function(string) { if (blackListMatch(keywordBlackList, string)) { console.log('拦截疑惑模块:', string); return; } // 调用原始接口 old_write.apply(document, arguments); } } /** * [黑名单般配] * @param {[Array]} blackList [黑名单] * @param {[String]} value [亟待表明的字符串] * @return {[Boolean]} [false -- 验证不经过,true -- 验证通过] */ function blackListMatch(blackList, value) { var length = blackList.length, i = 0; for (; i < length; i ) { // 创建黑名单正则 var reg = new RegExp(whiteList[i], 'i'); // 存在黑名单中,拦截 if (reg.test(value)) { return true; } } return false; }<span style="font-family: verdana, geneva;"> </span>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
```javascript
// 建立关键词黑名单
var keywordBlackList = [
  'xss',
  'BAIDU_SSP__wrapper',
  'BAIDU_DSPUI_FLOWBAR'
];
/**
* 重写单个 window 窗口的 document.write 属性
* @param  {[BOM]} window [浏览器window对象]
* @return {[type]}       [description]
*/
function resetDocumentWrite(window) {
  var old_write = window.document.write;
  window.document.write = function(string) {
    if (blackListMatch(keywordBlackList, string)) {
      console.log('拦截可疑模块:', string);
      return;
    }
    // 调用原始接口
    old_write.apply(document, arguments);
  }
}
/**
* [黑名单匹配]
* @param  {[Array]} blackList [黑名单]
* @param  {[String]} value    [需要验证的字符串]
* @return {[Boolean]}         [false -- 验证不通过,true -- 验证通过]
*/
function blackListMatch(blackList, value) {
  var length = blackList.length,
    i = 0;
  for (; i < length; i ) {
    // 建立黑名单正则
    var reg = new RegExp(whiteList[i], 'i');
    // 存在黑名单中,拦截
    if (reg.test(value)) {
      return true;
    }
  }
  return false;
}<span style="font-family: verdana, geneva;"> </span>

咱俩得以把 resetDocumentWrite 放入上文的 installHook 方法中,就会对近些日子window 及具备变化的 iframe 情况内的 document.write 实行重写了。

 

澳门新浦京娱乐场网站:前端安全,二零一六Ali高校招徕诚邀前端在线检验标题。//Method 1 对事件开展管理。那样做的补益是幸免了对每叁个a标签进行依次绑定,节省了光阴支出,其余代码更简短。
(function() {
    var b = document.body;
    var reg = /^(https?://)?([da-z.-] ).btaobaob.com([/w .-]*)*/?$/;

div.style // 对象

锁死 apply 和 call

接下去要介绍的这些是锁住原生的 Function.prototype.apply 和 Function.prototype.call 方法,锁住的意趣正是使之无法被重写。

此地要用到 Object.defineProperty ,用于锁死 apply 和 call。

动态脚本拦截

上面使用 MutationObserver 拦截静态脚本,除了静态脚本,与之对应的正是动态变化的脚本。

var script = document.createElement('script');
script.type = 'text/javascript';
script.src = 'http://www.example.com/xss/b.js';

document.getElementsByTagName('body')[0].appendChild(script); 

要堵住那类动态变化的台本,且拦截机会要在它插入 DOM 树中,试行之前,本来是足以监听 Mutation Events 中的 DOMNodeInserted 事件的。

    function doClick(event) {
        if (event.target.tagName == 'A') {
            event.preventDefault();
            var href = event.target.href;
            if (reg.exec(href)) {
                location.href = href;
            } else {
                if (window.confirm("非本地站点,是不是持续?")) {
                    location.href = href;
                }
            }
        }
    }
    b.onclick = doClick;
})();

</scrpit>

 

//Method 2
(function() {
    var hrefs = document.getElementsByTagName('a');
    for(var i=0; i <hrefs.length; i ) {
        var href = hrefs[i].getAttribute("href");
        hrefs[i].onclick = function(href) {
            return function() {
                var reg = /^(https?://)?([da-z.-] ).btaobaob.com([/w .-]*)*/?$/;
                if(reg.exec(href)) {
                    return true;
                } else {
                    return window.confirm("非本地站点,是还是不是继续?");
                }
            };
        }(href);
    }
})();

  1. 语义不一样等

Object.defineProperty

Object.defineProperty() 方法直接在一个目的上定义叁个新属性,大概涂改三个早已存在的习性, 并重临这一个目的。

JavaScript

Object.defineProperty(obj, prop, descriptor)

1
Object.defineProperty(obj, prop, descriptor)

其中:

  • obj – 须求定义属性的靶子
  • prop – 需被定义或涂改的属性名
  • descriptor – 需被定义或改变的习性的汇报符

作者们可以采用如下的代码,让 call 和 apply 不能够被重写。

JavaScript

// 锁住 call Object.defineProperty(Function.prototype, 'call', { value: Function.prototype.call, // 当且仅当仅当该属性的 writable 为 true 时,该属性本事被赋值运算符退换 writable: false, // 当且仅当该属性的 configurable 为 true 时,该属性技术够被退换,也能够被去除 configurable: false, enumerable: true }); // 锁住 apply Object.defineProperty(Function.prototype, 'apply', { value: Function.prototype.apply, writable: false, configurable: false, enumerable: true });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 锁住 call
Object.defineProperty(Function.prototype, 'call', {
  value: Function.prototype.call,
  // 当且仅当仅当该属性的 writable 为 true 时,该属性才能被赋值运算符改变
  writable: false,
  // 当且仅当该属性的 configurable 为 true 时,该属性才能够被改变,也能够被删除
  configurable: false,
  enumerable: true
});
// 锁住 apply
Object.defineProperty(Function.prototype, 'apply', {
  value: Function.prototype.apply,
  writable: false,
  configurable: false,
  enumerable: true
});

怎么要这么写啊?其实依然与上文的 重写 setAttribute 有关。

就算大家将原始 Element.prototype.setAttribute 保存在了三个闭包个中,但是还恐怕有奇技淫巧可以把它从闭包中给“偷出来”。

试一下:

JavaScript

(function() {})( // 保存原有接口 var old_setAttribute = Element.prototype.setAttribute; // 重写 setAttribute 接口 Element.prototype.setAttribute = function(name, value) { // 具体细节 if (this.tagName == 'SC凯雷德IPT' && /^src$/i.test(name)) {} // 调用原始接口 old_setAttribute.apply(this, arguments); }; )(); // 重写 apply Function.prototype.apply = function(){ console.log(this); } // 调用 setAttribute document.getElementsByTagName('body')[0].setAttribute('data-test','123');

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
(function() {})(
    // 保存原有接口
    var old_setAttribute = Element.prototype.setAttribute;
    // 重写 setAttribute 接口
    Element.prototype.setAttribute = function(name, value) {
        // 具体细节
        if (this.tagName == 'SCRIPT' && /^src$/i.test(name)) {}
        // 调用原始接口
        old_setAttribute.apply(this, arguments);
    };
)();
// 重写 apply
Function.prototype.apply = function(){
    console.log(this);
}
// 调用 setAttribute
document.getElementsByTagName('body')[0].setAttribute('data-test','123');

猜度上边生机勃勃段会输出什么?看看:
澳门新浦京娱乐场网站 15

居然重临了原生 setAttribute 方法!

那是因为大家在重写 Element.prototype.setAttribute 时最终有 old_setAttribute.apply(this, arguments);这一句,使用到了 apply 方法,所以大家再重写 apply ,输出 this ,当调用被重写后的 setAttribute 就足以从当中反向拿到原生的被保存起来的 old_setAttribute 了。

那般大家地方所做的嵌套 iframe 重写 setAttribute 就毫无意义了。

使用方面包车型大巴 Object.defineProperty 能够锁死 apply 和 类似用法的 call 。使之无法被重写,那么也就不能从闭包准将大家的原生接口偷出来。这一年才算真正含义上的中标重写了我们想重写的品质。

Mutation Events 与 DOMNodeInserted

打开 MDN ,第一句正是:

该特性已经从 Web 标准中删除,即便片段浏览器近日仍然支撑它,但恐怕会在以往的有个别时刻甘休补助,请尽可能不要采用该天性。

纵然无法用,也足以领悟一下:

document.addEventListener('DOMNodeInserted', function(e) {
  var node = e.target;
  if (/xss/i.test(node.src) || /xss/i.test(node.innerHTML)) {
    node.parentNode.removeChild(node);
    console.log('拦截可疑动态脚本:', node);
  }
}, true);

可是缺憾的是,使用方面包车型客车代码拦截动态变化的脚本,能够阻止到,可是代码也奉行了:DOMNodeInserted 以管窥天,能够监听有些DOM 范围内的组织变迁,与 MutationObserver 比较,它的实行机会更早。

澳门新浦京娱乐场网站 16

但是 DOMNodeInserted 不再建议使用,所以监听动态脚本的任务也要提交 MutationObserver

心疼的是,在其实实行进程中,使用 MutationObserver 的结果和 DOMNodeInserted 同样,能够监听拦截到动态脚本的更改,可是无法在剧本推行早先,使用 removeChild 将其移除,所以大家还索要观念别的措施。

View JavaScript Code

如a元素的href属性。

建构拦截上报

看守的招数也可能有生气勃勃部分了,接下去大家要确立二个叙述系统,替换上文中的 console.log() 日志。

陈诉系统有何样用啊?因为我们用到了白名单,关键字黑名单,那个数量都亟需不停的丰裕,靠的正是申报系统,将每一趟拦截的音讯传播服务器,不仅可以够让大家技师第有的时候间获知攻击的产生,更能够让我们不住采撷那类相关音信以便更加好的答问。

此处的身体力行作者用 nodejs 搭三个要命简短的服务器选拔 http 上报央浼。

先定义一个反馈函数:

JavaScript

/** * 自定义上报 -- 替换页面中的 console.log() * @param {[String]} name [阻挡类型] * @param {[String]} value [拦截值] */ function hijackReport(name, value) { var img = document.createElement('img'), hijackName = name, hijackValue = value.toString(), curDate = new Date().getTime(); // 上报 img.src = '' hijackName '&value=' hijackValue '&time=' curDate;

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* 自定义上报 -- 替换页面中的 console.log()
* @param  {[String]} name  [拦截类型]
* @param  {[String]} value [拦截值]
*/
function hijackReport(name, value) {
  var img = document.createElement('img'),
    hijackName = name,
    hijackValue = value.toString(),
    curDate = new Date().getTime();
  // 上报
  img.src = 'http://www.reportServer.com/report/?msg=' hijackName '&value=' hijackValue '&time=' curDate;

假定大家的服务器地址是 www.reportServer.com 这里,大家应用 img.src 发送一个http 央浼到服务器http://www.reportServer.com/report/ ,每一回会带上大家自定义的掣肘类型,拦截内容以至反映时间。

用 Express 搭 nodejs 服务器并写三个简便的选用路由:

JavaScript

var express = require('express'); var app = express(); app.get('/report/', function(req, res) { var queryMsg = req.query.msg, queryValue = req.query.value, queryTime = new Date(parseInt(req.query.time)); if (queryMsg) { console.log('拦截类型:'

  • queryMsg); } if (queryValue) { console.log('拦截值:' queryValue); } if (queryTime) { console.log('拦截时间:' req.query.time); } }); app.listen(3002, function() { console.log('HttpHijack Server listening on port 3002!'); });
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
var express = require('express');
var app = express();
app.get('/report/', function(req, res) {
    var queryMsg = req.query.msg,
        queryValue = req.query.value,
        queryTime = new Date(parseInt(req.query.time));
    if (queryMsg) {
        console.log('拦截类型:' queryMsg);
    }
    if (queryValue) {
        console.log('拦截值:' queryValue);
    }
    if (queryTime) {
        console.log('拦截时间:' req.query.time);
    }
});
app.listen(3002, function() {
    console.log('HttpHijack Server listening on port 3002!');
});

运转服务器,当有反馈发生,大家将会收到到如下数据:

澳门新浦京娱乐场网站 17

好接下去正是数据入库,剖析,增加黑名单,使用 nodejs 当然拦截产生时发送邮件公告技士等等,这几个就不再做张开。

 

 

<a href="//m.taobao.com" ></div>

HTTPS 与 CSP

谈起底再轻易谈谈 HTTPS 与 CSP。其实防范恫吓最佳的措施依然从后端入手,前端能做的实在太少。何况由于源码的展露,攻击者相当轻易绕过大家的守卫手腕。

重写 setAttribute 与 document.write

7、编写一个JavaScript函数,输入钦点项目标选拔器(仅需支撑id,class,tagName两种简单CSS选取器,不必要协作组合选取器)能够回来相配的DOM节点,需驰念浏览器宽容性和质量。

<script>

CSP

CSP 即是 Content Security Policy,翻译为剧情安全计策。那一个专门的工作与内容安全有关,主借使用来定义页面能够加载哪些财富,收缩XSS 的爆发。

MDN – CSP

重写原生 Element.prototype.setAttribute 方法

在动态脚本插入推行前,监听 DOM 树的扭转拦截它不行,脚本还是会举办。

那就是说大家要求向上寻觅,在剧本插入 DOM 树前的破获它,那正是成立脚本时那些机缘。

假使今后有二个动态脚本是这么创造的:

var script = document.createElement('script');
script.setAttribute('type', 'text/javascript');
script.setAttribute('src', 'http://www.example.com/xss/c.js');

document.getElementsByTagName('body')[0].appendChild(script);

而重写 Element.prototype.setAttribute 也是实用的:大家开掘此处运用了 setAttribute 方法,要是咱们能够改写这一个原生方法,监听设置 src 属性时的值,通过黑名单或然白名单推断它,就能够料定该标签的合法性了。

// 保存原有接口
var old_setAttribute = Element.prototype.setAttribute;

// 重写 setAttribute 接口
Element.prototype.setAttribute = function(name, value) {

  // 匹配到 <script src='xxx' > 类型
  if (this.tagName == 'SCRIPT' && /^src$/i.test(name)) {
    // 白名单匹配
    if (!whileListMatch(whiteList, value)) {
      console.log('拦截可疑模块:', value);
      return;
    }
  }

  // 调用原始接口
  old_setAttribute.apply(this, arguments);
};

// 建立白名单
var whiteList = [
'www.yy.com',
'res.cont.yy.com'
];

/**
 * [白名单匹配]
 * @param  {[Array]} whileList [白名单]
 * @param  {[String]} value    [需要验证的字符串]
 * @return {[Boolean]}         [false -- 验证不通过,true -- 验证通过]
 */
function whileListMatch(whileList, value) {
  var length = whileList.length,
    i = 0;

  for (; i < length; i  ) {
    // 建立白名单正则
    var reg = new RegExp(whiteList[i], 'i');

    // 存在白名单中,放行
    if (reg.test(value)) {
      return true;
    }
  }
  return false;
}

能够见到如下结果:能够戳我查看DEMO。(展开页面后展开调控台查看 console.log)

澳门新浦京娱乐场网站 18

重写 Element.prototype.setAttribute ,正是首先保存原有接口,然后当有成分调用 setAttribute 时,检查传入的 src 是或不是留存于白名单中,存在则放行,不设有则正是疑忌元素,实行上报并不给予实践。最终对放行的要素推行原生的 setAttribute ,也就是 old_setAttribute.apply(this, arguments);

上述的白名单相配也足以换到黑名单相配。

/**

var a = document.getElementByTagName('a');

HTTPS

可以预知实施 HTTP 胁制的根本原因,是 HTTP 公约未有主意对通讯对方的地方张开校验以致对数据完整性进行校验。借使能化解这些主题素材,则威迫将不可能自由产生。

HTTPS,是 HTTP over SSL 的情致。SSL 合同是 Netscape 在 1995年第三遍建议的用来缓慢解决传输层安全主题材料的网络合同,其主导是依据公钥密码学理论达成了对服务器居民身份注解、数据的私密性保护以至对数据完整性的校验等功能。

因为与本文首要内容关联性很小,关于更加多 CSP 和 HTTPS 的剧情能够活动谷歌(Google)。

 

本文到此截止,笔者也是读书前端安全那些上面赶紧,文章必然有所错误疏失及错误,小说的办法也是数不胜数防御措施中的一小部分,多数内容参谋下边作品,皆以精品小说,特别值得风流浪漫读:

  • 《web前端黑客工夫揭秘》
  • XSS 前端防火墙体系1~3
  • 【HTTP劫持和DNS劫持】实际JS对抗
  • 浅谈DNS劫持
  • HTTP Request Hijacking

 

运用 Javascript 写的三个防威逼组件,已上盛传 Github – httphijack.js,款待感兴趣看看顺手点个 star ,本文示例代码,防备措施在组件源码中皆可找到。

别的组件处于测验修改阶段,未在生养情形使用,并且使用了多数 HTML5 才支撑的 API,兼容性是个难题,仅供就学调换。

到此本文截至,借使还会有怎么着难点照旧建议,可以多多沟通,原创文章,文笔有限,才疏学浅,文中若有不正之处,万望告知。

打赏援救本人写出越来越多好小说,谢谢!

打赏小编

 

* @param selector {String} 传入的CSS选择器。

a.href // “

打赏扶助笔者写出更加多好小说,感谢!

任选生龙活虎种支付办法

澳门新浦京娱乐场网站 19 澳门新浦京娱乐场网站 20

2 赞 10 收藏 1 评论

重写嵌套 iframe 内的 Element.prototype.setAttribute

本来,上边的写法假如 old_setAttribute = Element.prototype.setAttribute 暴露给攻击者的话,直接使用old_setAttribute 就能够绕过大家重写的格局了,所以这段代码必得包在一个闭包内。

当然如此也不保险,尽管眼下窗口下的 Element.prototype.setAttribute 已经被重写了。可是还是有一手能够得到原生的 Element.prototype.setAttribute ,只须求三个新的 iframe 。

var newIframe = document.createElement('iframe');
document.body.appendChild(newIframe);

Element.prototype.setAttribute = newIframe.contentWindow.Element.prototype.setAttribute;

透过那些办法,可以另行得到原生的 Element.prototype.setAttribute ,因为 iframe 内的蒙受和外围 window 是全然切断的。wtf?

澳门新浦京娱乐场网站 21

怎么做?大家看见创制iframe 用到了 createElement,那么是不是能够重写原生 createElement 呢?不过除外createElement 还有 createElementNS ,还也是有望是页面上曾经存在 iframe,所以不合适。

那就在每当新创造二个新 iframe 时,对 setAttribute 举行维护重写,这里又有用到 MutationObserver :

/**
 * 使用 MutationObserver 对生成的 iframe 页面进行监控,
 * 防止调用内部原生 setAttribute 及 document.write
 * @return {[type]} [description]
 */
function defenseIframe() {
  // 先保护当前页面
  installHook(window);
}

/**
 * 实现单个 window 窗口的 setAttribute保护
 * @param  {[BOM]} window [浏览器window对象]
 * @return {[type]}       [description]
 */
function installHook(window) {
  // 重写单个 window 窗口的 setAttribute 属性
  resetSetAttribute(window);

  // MutationObserver 的不同兼容性写法
  var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;

  // 该构造函数用来实例化一个新的 Mutation 观察者对象
  // Mutation 观察者对象能监听在某个范围内的 DOM 树变化
  var observer = new MutationObserver(function(mutations) {
    mutations.forEach(function(mutation) {
      // 返回被添加的节点,或者为null.
      var nodes = mutation.addedNodes;

      // 逐个遍历
      for (var i = 0; i < nodes.length; i  ) {
        var node = nodes[i];

        // 给生成的 iframe 里环境也装上重写的钩子
        if (node.tagName == 'IFRAME') {
          installHook(node.contentWindow);
        }
      }
    });
  });

  observer.observe(document, {
    subtree: true,
    childList: true
  });
}

/**
 * 重写单个 window 窗口的 setAttribute 属性
 * @param  {[BOM]} window [浏览器window对象]
 * @return {[type]} [description]
 */
function resetSetAttribute(window) {
  // 保存原有接口
  var old_setAttribute = window.Element.prototype.setAttribute;

  // 重写 setAttribute 接口
  window.Element.prototype.setAttribute = function(name, value) {
    ...
  };
} 

我们定义了三个 installHook 方法,参数是二个 window ,在此个格局里,大家将重写传入的 window 下的 setAttribute ,并且安装多个 MutationObserver ,并对此窗口下未来大概创造的 iframe 实行监听,假诺前景在这里 window 下创造了二个iframe ,则对新的 iframe 也装上 installHook 方法,以此实行罕有爱戴。

* @return {Array}

a.getAttribute('href') // “//m.taobao.com”,跟HTML代码中完全旭日东升致

至于小编:chokcoco

澳门新浦京娱乐场网站 22

经不住大运似水,逃然而此间少年。 个人主页 · 笔者的稿子 · 63 ·    

澳门新浦京娱乐场网站 23

 

*/

</scrpit>

重写 document.write

遵照上述的主意,大家能够持续掘进一下,还应该有怎样措施能够重写,以便对页面实行更好的保证。

document.write 是二个很科学选用,注入攻击者,平日会利用这么些点子,往页面上注入一些弹窗广告。

小编们能够重写 document.write ,使用重要词黑名单对剧情实行相配。

怎样比较相符当黑名单的严重性字呢?我们得以看看一些广告比相当多的页面:

澳门新浦京娱乐场网站 24

这里在页面最底部放置了二个iframe ,里面装了广告代码,这里的最外层的 id 名id="BAIDU_SSP__wrapper_u2444091_0" 就很切合成为大家看清是不是是恶意代码的三个注解,假若我们已经依据拦截上报出价格罗到了一群黑名单列表:

// 建立正则拦截关键词
var keywordBlackList = [
'xss',
'BAIDU_SSP__wrapper',
'BAIDU_DSPUI_FLOWBAR'
];

接下去大家只供给动用那么些根本字,对 document.write 传入的剧情开展正则判定,就会鲜明是还是不是要堵住document.write 这段代码。 

```javascript
// 建立关键词黑名单
var keywordBlackList = [
  'xss',
  'BAIDU_SSP__wrapper',
  'BAIDU_DSPUI_FLOWBAR'
];

/**
 * 重写单个 window 窗口的 document.write 属性
 * @param  {[BOM]} window [浏览器window对象]
 * @return {[type]}       [description]
 */
function resetDocumentWrite(window) {
  var old_write = window.document.write;

  window.document.write = function(string) {
    if (blackListMatch(keywordBlackList, string)) {
      console.log('拦截可疑模块:', string);
      return;
    }

    // 调用原始接口
    old_write.apply(document, arguments);
  }
}

/**
 * [黑名单匹配]
 * @param  {[Array]} blackList [黑名单]
 * @param  {[String]} value    [需要验证的字符串]
 * @return {[Boolean]}         [false -- 验证不通过,true -- 验证通过]
 */
function blackListMatch(blackList, value) {
  var length = blackList.length,
    i = 0;

  for (; i < length; i  ) {
    // 建立黑名单正则
    var reg = new RegExp(whiteList[i], 'i');

    // 存在黑名单中,拦截
    if (reg.test(value)) {
      return true;
    }
  }
  return false;
} 

我们能够把 resetDocumentWrite 放入上文的 installHook 方法中,就能够对现阶段 window 及持有更动的 iframe 境遇内的 document.write 进行重写了。

var query = function(selector){

  1. 单向同步关系

 

//重临查找到的节点数组

value是一个极为优异的attribute/property。

锁死 apply 和 call

接下去要介绍的这一个是锁住原生的 Function.prototype.apply 和 Function.prototype.call 方法,锁住的情趣正是使之不可能被重写。

那边要用到 Object.defineProperty ,用于锁死 apply 和 call。

return [];

<input value = "cute" />

 

}

<script>

Object.defineProperty

Object.defineProperty() 方法直接在二个目的上定义一个新属性,可能修改三个早就存在的属性, 并重返那一个目的。

Object.defineProperty(obj, prop, descriptor)

其中: 

  • obj – 须求定义属性的靶子
  • prop – 需被定义或涂改的属性名
  • descriptor – 需被定义或改换的性格的呈报符

大家能够行使如下的代码,让 call 和 apply 不可能被重写。

// 锁住 call
Object.defineProperty(Function.prototype, 'call', {
  value: Function.prototype.call,
  // 当且仅当仅当该属性的 writable 为 true 时,该属性才能被赋值运算符改变
  writable: false,
  // 当且仅当该属性的 configurable 为 true 时,该属性才能够被改变,也能够被删除 
  configurable: false,
  enumerable: true
});
// 锁住 apply
Object.defineProperty(Function.prototype, 'apply', {
  value: Function.prototype.apply,
  writable: false,
  configurable: false,
  enumerable: true
}); 

为啥要如此写啊?其实依然与上文的 重写 setAttribute 有关。

纵然我们将原始 Element.prototype.setAttribute 保存在了叁个闭包此中,但是还应该有奇技淫巧能够把它从闭包中给“偷出来”。

试一下:

(function() {})(
    // 保存原有接口
    var old_setAttribute = Element.prototype.setAttribute;
    // 重写 setAttribute 接口
    Element.prototype.setAttribute = function(name, value) {
        // 具体细节
        if (this.tagName == 'SCRIPT' && /^src$/i.test(name)) {}
        // 调用原始接口
        old_setAttribute.apply(this, arguments);
    };
)();
// 重写 apply
Function.prototype.apply = function(){
    console.log(this);
}
// 调用 setAttribute
document.getElementsByTagName('body')[0].setAttribute('data-test','123'); 

思疑上边一日千里段会输出什么?看看:
澳门新浦京娱乐场网站 25

依旧重返了原生 setAttribute 方法!

那是因为我们在重写 Element.prototype.setAttribute 时最终有 old_setAttribute.apply(this, arguments);这一句,使用到了 apply 方法,所以大家再重写 apply ,输出 this ,当调用被重写后的 setAttribute 就足以从当中反向得到原生的被保存起来的 old_setAttribute 了。

与此相类似大家地点所做的嵌套 iframe 重写 setAttribute 就毫无意义了。

动用方面的 Object.defineProperty 可以锁死 apply 和 类似用法的 call 。使之不可能被重写,那么也就无法从闭包上校大家的原生接口偷出来。那一年才算真正意义上的打响重写了大家想重写的习性。

澳门新浦京娱乐场网站 26澳门新浦京娱乐场网站 27

var input = document.getElementByTagName('input');

 

<!DOCTYPE html>
<html>

//若property未有设置,则结果是attribute

确立拦截上报

防范的手腕也会有一点了,接下去大家要建构贰个反馈系统,替换上文中的 console.log() 日志。

申报系统有怎么着用吧?因为我们用到了白名单,关键字黑名单,那一个数量都亟待不断的拉长,靠的正是举报系统,将每回拦截的信息传播服务器,不只能够让大家技士第不常间得知攻击的爆发,更能够让我们不停采撷那类相关音信以便更加好的作答。

那边的示范小编用 nodejs 搭几个可怜简便的服务器接纳http 上报告请示求。

先定义贰个反映函数:

/**
 * 自定义上报 -- 替换页面中的 console.log()
 * @param  {[String]} name  [拦截类型]
 * @param  {[String]} value [拦截值]
 */
function hijackReport(name, value) {
  var img = document.createElement('img'),
    hijackName = name,
    hijackValue = value.toString(),
    curDate = new Date().getTime();

  // 上报
  img.src = 'http://www.reportServer.com/report/?msg='   hijackName   '&value='   hijackValue   '&time='   curDate;
}

只要大家的服务器地址是 www.reportServer.com 这里,我们运用 img.src 发送三个http 诉求到服务器http://www.reportServer.com/report/ ,每一遍会带上大家自定义的阻挠类型,拦截内容以致反映时间。

用 Express 搭 nodejs 服务器并写三个简约的选取路由:

var express = require('express');
var app = express();

app.get('/report/', function(req, res) {
    var queryMsg = req.query.msg,
        queryValue = req.query.value,
        queryTime = new Date(parseInt(req.query.time));

    if (queryMsg) {
        console.log('拦截类型:'   queryMsg);
    }

    if (queryValue) {
        console.log('拦截值:'   queryValue);
    }

    if (queryTime) {
        console.log('拦截时间:'   req.query.time);
    }
});

app.listen(3002, function() {
    console.log('HttpHijack Server listening on port 3002!');
});

运营服务器,当有反映产生,我们将会接到到如下数据:

澳门新浦京娱乐场网站 28

好接下去就是多少入库,深入分析,增加黑名单,使用 nodejs 当然拦截产生时发送邮件通告程序猿等等,这个就不再做打开。

<head>
    <title></title>
</head>

input.value //cute

 

<body>
    <div class="test" name="a"></div>
    <div class="test" name="b"></div>
    <div class="test" name="c"></div>
    <div class="test" name="d"></div>
    <div class="test" name="e"></div>

input.getAttribute('value'); //cute

HTTPS 与 CSP

末尾再简单谈谈 HTTPS 与 CSP。其实防守要挟最好的办法依旧从后端出手,前端能做的实在太少。並且由于源码的揭露,攻击者相当的轻巧绕过大家的看守花招。

   <script type="text/javascript">
        var query = function(selector) {
            var reg_id = /^#[w] /;
            var reg_class = /^.[w] /;

 

CSP

CSP 便是Content Security Policy,翻译为内容安全战术。那一个专门的学业与内容安全有关,首假设用来定义页面能够加载哪些能源,降低XSS 的产生。

MDN – CSP

            var elems;
            if (document.querySelectorAll) {
                return document.querySelectorAll(selector);
            }

input.value = 'hello';

HTTPS

能够实行HTTP 威胁的根本原因,是 HTTP 协议未有艺术对通讯对方的地位举办校验以致对数据完整性举行校验。假设能一下子就解决了那么些主题素材,则勒迫将不可能任意发生。

HTTPS,是 HTTP over SSL 的意思。SSL 协议是 Netscape 在 一九九一年第二次提议的用来缓和传输层安全难题的互联网公约,其基本是基于公钥密码学理论完毕了对服务器身份ID明、数据的私密性爱戴以至对数据完整性的校验等功能。

因为与本文首要内容关联性比非常的小,关于更加多CSP 和 HTTPS 的内容能够活动谷歌(Google)。

 

本文到此停止,小编也是阅读前端安全那些方面尽快,作品必然有所错误疏失及错误,小说的艺术也是数不清监守措施中的一小部分,多数内容参谋上边文章,都以精品文章,非常值得风流潇洒读:

  • 《web前端红客技艺揭秘》
  • XSS 前端防火墙种类1~3
  • 【HTTP劫持和DNS劫持】实际JS对抗
  • 浅谈DNS劫持
  • HTTP Request Hijacking

 

动用 Javascript 写的二个防威逼组件,已上传来 Github – httphijack.js,款待感兴趣看看顺手点个 star ,本文示例代码,防止方法在组件源码中皆可找到。

别的组件处于测量检验修改阶段,未在生产条件使用,而且动用了累累 HTML5 才支撑的 API,宽容性是个难点,仅供就学调换。

到此本文甘休,假诺还会有何疑点依然建议,能够多多调换,原创小说,文笔有限,才疏学浅,文中若有不正之处,万望告知。

            if (reg_id.test(selector)) {
                elems = document.getElementById(selector.slice(1));
            } else if (reg_class.test(selector)) {
                elems = getElementsByClassName(selector.slice(1));
            } else {
                elems = document.getElementsByTagName(selector);
            }

//若value属性已经设置,则attribute不改变,property变化,成分上实际的功力是property优先

            return elems;
        };

input.value //hello

        function getElementsByClassName(className) {
            var arr = document.getElementsByTagName("*"),
                result;
            for (var i = 0, len = arr.length; i < len; i ) {
                if (arr[i].className.indexOf(className) != -1) {
                    result.push(arr[i]);
                }
            }
            return result;
        }

input.getAttribute('value'); //cute

        console.log(query(".test"));
</script>

</scrpit>

</body>

除开,checkbox的来得状态由checked和indeterminate七个property决定,而只有贰个名叫checked的property,这种情景下property是更完美的访问模型。

</html>

三、特殊现象

View Code

1.mutation

澳门新浦京娱乐场网站 29澳门新浦京娱乐场网站 30

运用mutation observer,只可以监测到attribute变化。

var query = function(selector) {
        var rId = /^#/;
        var rCls = /^./;
        //标准浏览器
        if (window.addEventListener) {
            return document.querySelectorAll(selector);
        }
        //IE
        if (rId.test(selector)) {
            return document.getElementById(selector.slice(1));
        }
        if (rCls.test(selector)) {
            return getElementsByClass(selector.slice(1));
        }
        return document.getELementsByTagName(selector);

var observer = new MutationObserver(function(mutations){

    };

for(var i = 0; i < mutations.length; i ) {

    var getElementsByClass = function(searchClass, node, tag) {
        var classElements = new Array();
        if (node == null)
            node = document;
        if (tag == null)
            tag = '*';
        var els = node.getElementsByTagName(tag);
        var elsLen = els.length;
        var pattern = new RegExp("(^|\s)"   searchClass   "(\s|$)");
        for (i = 0, j = 0; i < elsLen; i ) {
            if (pattern.test(els[i].className)) {
                console.log(true);classElements[j] = els[i];
                j ;
            }
        }
        return classElements;
    }; 

var mutation = mutations[i];

View Code

console.log(mutation.attributeName);

8、一个页面上有大量的图片,加载非常的慢,你有哪些措施优化那一个图片的加载,给顾客越来越好的经验。 

}

a. CSS Coca Colas:将三个网页中关系的繁琐图片,整合到一张大图中,然后利用CSS能力表现出来。那样一来,收缩了大器晚成切页面图片的高低,并且能降低式网球页http哀告次数,进而大大地增加网页的品质。

});

b. 压缩图片

observer.observe(element,{attributes:true});

c. 功效图片优先加载

element.prop1 = 'aa' // 不会接触

d. 图片格式优化(JPEG,GIF,和PNG):对于产品图片品质供给非常高,使用JPEG格式,用GIF做动画或是装饰性小图,PNG相同的时间也专长管理差不离地装饰图而只需相当小的体量

element.setAttribute('attr1', 'aa') //会触发

 

2.custom element

9、使用 JavaScript 的 Promise 格局落到实处延迟3秒输出 

在采纳WebComponents时,能够定义attribute和property,两个可以相互反射,也能够全非亲非故联。

澳门新浦京娱乐场网站 31澳门新浦京娱乐场网站 32

var MyElementProto = Object.create(HTMLElement.prototype, {

// 先封装三个再次回到promise的函数
var Promise = function () {
   
};

createdCallback : {

Promise.prototype.then = function (onResolved, onRejected) {
    this.onResolved = onResolved;
    this.onRejected = onRejected;
    return this;
};

value : function() { }

Promise.prototype.resolve = function (value) {
   this.onResolved(value);
   return this;
};
 
Promise.prototype.reject = function (error) {
    this.onRejected(error);
    return this;
};

}

new Promise().then(function(value) {
    setTimeout(function() {
        console.log(value);
    }, 3000);
}, function(error) {
    alert("error");
}).resolve("3 sec output.");

});

View Code

 

10、落成二个页面

//定义property

澳门新浦京娱乐场网站 33澳门新浦京娱乐场网站 34

Object.defineProperty(MyElementProto,'prop1', {

<!DOCTYPE html>
<html>
<head>
    <title></title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body style="width:960px; margin: 20px auto;">
    <div id="nav" style="height: 80px;text-align: center;font-size: 3em;border-bottom: solid #DDDDDD;">Alibaba面试题</div>
    <div id = "Content">
        <div id = "sidebar" style="width:20%; float: left;">
            <ul>
                <li style="list-style: none;"><a href="" style="text-decoration: none;">前端程序猿面试题</a></li>
                <li style="list-style: none;"><a href="" style="text-decoration: none;">设计员面试题</a></li>
                <li style="list-style: none;"><a href="" style="text-decoration: none;">java面试题</a></li>
            </ul>    
        </div>
        <div id = "main" style="width:80%;">
            <table style="border-collapse:collapse;">
                <tr> 
                    <th  style="border:1px solid black; width:250px; height:40px;">小编是标题风度翩翩</th>
                    <th  style="border:1px solid black; width:90px; height:40px;">标题二</th>
                    <th  style="border:1px solid black; width:90px; height:40px;">三</th>
                </tr>
                <t>
                    <td style="border:1px solid black; width:250px; height:40px;">内容</td>
                    <td style="border:1px solid black; width:250px; height:40px;">内容</td>
                    <td style="border:1px solid black; width:250px; height:40px;">内容</td>
                </tr>
            </table>
        </div>
    </div>
</body>
</html>

get:function(){

View HTML Code

return //

 

},

11、个人的github地址 

set:function(){

console.log('property change');//do something

}

});

 

//定义attribute

MyElementProto.attributeChangedCallback = function(attr, oldVal, newVal) {

if(attr === 'attr1') {

console.log('attribute change');//do something

}

};

 

window.MyElement = document.registerElement('my-element', {

prototype: MyElementProto

});

本文由澳门新浦京娱乐场网站发布于新浦京娱乐场官网,转载请注明出处:澳门新浦京娱乐场网站:前端安全,二零一六A