澳门新萄京官方网站-www.8455.com-澳门新萄京赌场网址

澳门新萄京官方网站前端安全,2015阿里校园招聘

2019-11-24 作者:澳门新萄京赌场网址   |   浏览(179)

JavaScript 防 http 劫持与 XSS

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

正文我: 伯乐在线 - chokcoco 。未经小编许可,防止转发!
迎接参预伯乐在线 专栏编辑者。

用作前端,长期以来都了然HTTP劫持XSS跨站脚本(Cross-site scripting)、CSRF跨站请求伪造(Cross-site request forgery卡塔 尔(英语:State of Qatar)。可是一直都并未有长远钻研过,本月同事的分享会有的时候提起,作者也对这一块很感兴趣,便浓重钻研了生机勃勃番。

方今用 JavaScript 写了七个零器件,能够在后边贰个层面堤防部分 HTTP 威胁与 XSS。

理当如此,防范那几个挟制最棒的艺术只怕从后端出手,前端能做的实在太少。并且由于源码的展露,攻击者相当轻易绕过我们的防备花招。可是那不代表我们去明白那块的相干文化是没意义的,本文的过多主意,用在其余省方也是大有成效。

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

接下去步向正文。

用作前端,一如既往都清楚HTTP劫持XSS跨站脚本(Cross-site scripting)、CSRF跨站请求伪造(克罗斯-site request forgery卡塔 尔(英语:State of Qatar)。可是一向都没有浓厚斟酌过,后一个月同事的分享会有的时候提起,小编也对这一块很感兴趣,便深远钻研了风姿罗曼蒂克番。

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 ,也等于足以垄断(monopoly卡塔 尔(英语:State of Qatar)父页面的跳转。

三个属性分别能够又简写为 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 是无法获得父级页面包车型大巴 UEscortL 的,这时,需求接收document.referrer

经过 document.referrer 能够得到跨域 iframe 父页面的URL。

JavaScript

// 建构白名单 var whiteList = [ 'www.aaa.com', 'res.bbb.com' ]; if (self != top) { var // 使用 document.referrer 能够得到跨域 iframe 父页面包车型大巴 URAV4L 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');

校正 UWranglerL 参数绕过运行商标志

那般就完了吧?未有,我们纵然重定向了父页面,可是在重定向的历程中,既然第三次能够嵌套,那么那二遍重定向的长河中页面只怕又被 iframe 嵌套了,真尼玛蛋疼。

自然运转商这种要挟平常也许有迹可循,最健康的手法是在页面 U牧马人L 中安装一个参数,举例  ,其中 iframe_hijack_redirected=1 表示页面已经被劫持过了,就不再嵌套 iframe 了。所以依照那天本性,大家得以改写我们的 UEscortL ,使之看上去已经被要挟了:

JavaScript

var flag = 'iframe_hijack_redirected'; // 当前页面存在于多少个 iframe 中 // 此处需求树立三个白名单相称规则,白名单暗中同意放行 if (self != top) { var // 使用 document.referrer 能够获得跨域 iframe 父页面包车型大巴 U途乐L 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,依照深入分析那些 UGL450L ,不断增加我们的幸免手段,那些后文仲聊起。

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>

除开一些未列出来的要命少见生僻的流入方式,大多数都以 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 keywordBlackList = [ '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(keyword布莱克List, 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 面临错综复杂的业务供给,数13遍回调的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 对象的数组,第3个参数则是其风度翩翩观望者对象自己。

故而,使用 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> 是页面加载意气风发始发就存在的静态脚本(查看页面结构卡塔 尔(英语:State of Qatar),大家使用 MutationObserver 能够在本子加载之后,实施早前那几个小时段对其内容做正则相称,发现恶意代码则 removeChild() 掉,使之不可能实践。

window.top

回去窗口连串中的最顶层窗口的引用。

对于非同源的域名,iframe 子页面无法透过 parent.location 也许 top.location 得到现实的页面地址,可是能够写入 top.location ,也正是可以决定父页面包车型客车跳转。

四个特性分别能够又简写为 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 是无法获得父级页面包车型地铁 U中华VL 的,那个时候,必要采用document.referrer

透过 document.referrer 能够获得跨域 iframe 父页面包车型地铁UOdysseyL。

// 建立白名单
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 事件的。

校勘 ULANDL 参数绕过运转商标识

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

当然运转商这种抑低日常也可以有案可查,最健康的花招是在页面 ULANDL 中安装八个参数,例如  ,其中 iframe_hijack_redirected=1 表示页面已经被威胁过了,就不再嵌套 iframe 了。所以听他们讲那些特点,我们能够改写我们的 U奥迪Q3L ,使之看上去已经被威逼了:

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 中的 URubiconL,依照剖析那个 U中华VL ,不断巩固大家的警备花招,这些后文子禽提及。

6、天猫商城首页要求完结那样一个作用,对于页面上非taobao.com域名下的链接,在客户点击时,必要在链接处弹出提示框,提醒客商此链接非天猫商城域名下的链接,并予以客商采纳是否持续访谈。若是客商确认继续访谈,则在新窗口展开链接。请写出相应的代码。 

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>

除了一些未列出来的不多见生僻的注入格局,大部分都是 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普拉多IPT' && /^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 keyword布莱克List = [ '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 进行重写了。

 

//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本田UR-VIPT' && /^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 在 一九九一年第叁次提出的用于化解传输层安全难题的互联网公约,其基本是依赖公钥密码学理论实现了对服务器身份认证、数据的私密性珍惜以至对数据完整性的校验等职能。

因为与本文首要内容关联性一点都不大,关于更加多 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 在 一九九四年第一遍提议的用来减轻传输层安全主题素材的网络合同,其主干是基于公钥密码学理论完毕了对服务器身份证明、数据的私密性爱戴甚至对数据完整性的校验等效用。

因为与本文首要内容关联性比较小,关于越来越多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[澳门新萄京官方网站前端安全,2015阿里校园招聘前端在线测验题目。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 百事可乐s:将贰个网页中关系的零碎图片,整合到一张大图中,然后使用CSS技艺展现出来。那样一来,裁减了整个页面图片的大大小小,並且能减小网页http哀告次数,进而大大地做实网页的习性。

});

b. 压缩图片

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

c. 功用图片优先加载

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

d. 图片格式优化(JPEG,GIF,和PNG卡塔 尔(英语:State of Qatar):对于付加物图片品质必要非常高,使用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

});

本文由澳门新萄京官方网站发布于澳门新萄京赌场网址,转载请注明出处:澳门新萄京官方网站前端安全,2015阿里校园招聘

关键词: