构造技巧
利用字符编码
绕过长度限制
利用事件(Event)来缩短所需要的字节数(oninput,onclick,onmouseenter)
location.hash 根据HTTP协议,location.hash的内容不会在HTTP包中发送,所以服务器端的Web日志中并不会记录下location.hash里的内容,更好地隐藏了真实的意图。
利用注释符绕过长度限制。比如我们能控制两个文本框,第二个文本框允许写入更多的字节。此时可以利用HTML的“注释符号”,把两个文本框之间的HTML代码全部注释掉,从而“打通”两个<input>标签。
使用base标签定义页面上的所有使用“相对路径”标签的hosting地址
在有的技术文档中,提到<base>标签只能用于<head>标签之内,其实这是不对的。<base>标签可以出现在页面的任何地方,并作用于位于该标签之后的所有标签。
攻击者如果在页面中插入了<base>标签,就可以通过在远程服务器上伪造图片、链接或脚本,劫持当前页面中的所有使用“相对路径”的标签。
Windows.name
对当前窗口的window.name对象赋值,没有特殊字符的限制。因为window对象是浏览器的窗体,而并非document对象,因此很多时候window对象不受同源策略的限制。攻击者利用这个对象,可以实现跨域、跨页面传递数据。在某些环境下,这种特性将变得非常有用。
flash xss
在Flash中是可以嵌入ActionScript脚本
由于Flash文件如此危险,所以在实现XSSFilter时,一般都会禁用<embed>、<object>等标签。后者甚至可以加载ActiveX控件,能够产生更为严重的后果。
如果网站的应用一定要使用Flash怎么办?一般来说,如果仅仅是视频文件,则要求转码为“flv文件”。flv文件是静态文件,不会产生安全隐患。如果是带动态脚本的Flash,则可以通过Flash的配置参数进行限制。
限制Flash动态脚本的最重要的参数是“allowScriptAccess”,这个参数定义了Flash能否与HTML页面进行通信。它有三个可选值:
always,对与HTML的通信也就是执行JavaScript不做任何限制;
sameDomain,只允许来自于本域的Flash与Html通信,这是默认值;
never,绝对禁止Flash与页面通信。
使用always是非常危险的,一般推荐使用never。如果值为sameDomain的话,请务必确保Flash文件不是用户传上来的。
allowNet-working这个参数能控制Flash与外部网络进行通信。它有三个可选值:
all,允许使用所有的网络通信,也是默认值;
internal,Flash不能与浏览器通信如navi-gateToURL,但是可以调用其他的API;
none,禁止任何的网络通信。
一般建议此值设置为none或者internal。设置为all可能带来安全问题。
防御
HTTPonly解决xss后的cookie劫持攻击
一个Cookie的使用过程如下。
Step1:浏览器向服务器发起请求,这时候没有Cookie。
Step2:服务器返回时发送Set-Cookie头,向客户端浏览器写入Cookie。
Step3:在该Cookie到期前,浏览器访问该域下的所有页面,都将发送该Cookie。
HttpOnly是在Set-Cookie时标记的
服务器可能会设置多个Cookie(多个key-value对),而HttpOnly可以有选择性地加在任何一个Cookie值上。
输入检查
输入检查的逻辑,必须放在服务器端代码中实现。如果只是在客户端使用JavaScript进行输入检查,是很容易被攻击者绕过的。目前Web开发的普遍做法,是同时在客户端JavaScript中和服务器端代码中实现相同的输入检查。客户端JavaScript的输入检查,可以阻挡大部分误操作的正常用户,从而节约服务器资源。
在XSS的防御上,输入检查一般是检查用户输入的数据中是否包含一些特殊字符,如<、>、’、”等。如果发现存在特殊字符,则将这些字符过滤或者编码。
比较智能的“输入检查”,可能还会匹配XSS的特征。比如查找用户数据中是否包含了“<script>”、“javascript”等敏感字符。
输出检查
编码转义
HTMLencode JavaScriptencode 在PHP中,有htmlentities()和htmlspe-cialchars()两个函数可以满足安全要求。
在HTML标签中输出:对变量使用HTMLencode
在HTML属性中输出:采用HTMLencode
在<script>标签中输出:JavaScriptencode
在事件中输出:JavaScriptencode
在CSS中输出:OWASP ESAPI中的encodeForCSS()函数,其实现原理类似于ESAPI.encoder().encode-ForJavaScript()函数,除了字母、数字外的所有字符都被编码成十六进制形式“\uHH”。
在地址中输出:在URL的path(路径)或者search(参数)中输出,使用URLEncode即可。如果变量是整个URL,则应该先检查变量是否以“http”开头(如果不是则自动添加),以保证不会出现伪协议类的XSS攻击。在此之后,再对变量进行URLEncode,即可保证不会有此类的XSS发生了。
过滤富文本
在过滤富文本时,“事件”应该被严格禁止,因为“富文本”的展示需求里不应该包括“事件”这种动态效果。而一些危险的标签,比如<iframe>、<script>、<base>、<form>等,也是应该严格禁止的。在标签的选择上,应该使用白名单,避免使用黑名单。
尽可能禁止用户自定义CSS与style
防御DOM based xss
首先,在“$var”输出到<script>时,应该执行一次javascriptEncode;其次,在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()
需要重点关注这几个地方的参数是否可以被用户控制。
除了服务器端直接输出变量到JavaScript外,还有以下几个地方可能会成为DOM Based XSS的输入点,也需要重点关注。
页面中所有的inputs框
window.location(href、hash等)
window.name ?document.referrer
document.cookie ?localstorage
XMLHttpRequest返回的数据
风险
一般来说,存储型XSS的风险会高于反射型XSS。因为存储型XSS会保存在服务器上,有可能会跨页面存在。它不改变页面URL的原有结构,因此有时候还能逃过一些IDS的检测。
调试JS工具和辅助测试工具
firebug
IE 8 Developer Tools
Fiddler
HTTPwatch
网友评论