XSS攻击思路
XSS的本质还是一种”HTML“漏洞。用户的数据被当成了HTML的一部分来执行,从而混淆了原有的语义,产生了新的语义。如果未对用户的输入做任何处理,那么会直接产生XSS攻击漏洞。
通过特定标签实现攻击
在事件中输出
onclick
在URL地址中构造
将XSS攻击代码通过URLEncode进行编码,然后放在URL中实施攻击。
在地址输出中:
<a href="http://www.test.com/?test=$var">test</a>
可能的攻击方法
<a href="http://www.test.com/?test=" onclick=alert(1)"">test</a>
构造伪协议实施攻击
<a href="javascript:alert(1);">test</a>
除了javascript作为伪协议可以执行代码外,也有其他的伪协议可能导致脚本运行。
利用字符编码
var redirectUrl="";alert(/XSS/);";
将
"
进行了转义,得到一个Unicode字符,因此,实际上得到的结果是这样的
<script>%c1";alert(/XSS/);</script>
绕过长度限制
对用户输入的内容进行长度限制,使攻击者连一个完整的函数都无法写完,XSS攻击可能无法成功。但是依然存在风险点,攻击者可以利用事件(Event)来缩短所需要的字节数。
$var输出为:"onclick=alert(1)//
<input type=text value="" "onclick=alert(1)//"/>
当用户点击文本框,alert将被执行。
但利用”事件“能够缩短的字节数是有限的,最好的办法是把XSS Payload写到别处,再通过简单的代码加载这段XSS Payload。
最常用的一个“藏代码”的地方,就是“location.hash”。而且根据HTTP协议,location.hash的内容不会在HTTP包中发送,所以服务端的web日志中并不会记录下location.hash里的内容,从而也更好地隐藏了黑客的真实意图。
$var输出为: " onclick="eval(location.hash.substr(1))
输出后的HTML是:
<input type="text" value="" onclick="eval(location.hash.substr(1))" />
因为location.hash的第一个字符是#
,所以必须去除第一个字符才行。此时构造出的XSS URL为:
http://www.a.com/test.html#alert(1)
location.hash本身没有长度限制,但是浏览器的地址栏是有长度限制的,不过这个长度已经足够写很长的XSS Payload了。要是地址栏的长度也不够用, 还可以再使用
多个输入框使用注释符绕过
<base>
标签
windows.name
检查
代码过滤
对于用户输入的检查的逻辑,必须放在服务端代码中实现,如果只是在客户端使用JavaScript进行输入检查,是很容易被被攻击者绕过的。目前Web开发的普遍做法,是同时在客户端JavaScript中和服务器端代码中实现相同的输入检查。客户端JavaScript的输入检查,可以阻挡大部分误操作的正常用户,从而节约服务器资源。
对输入进行特征匹配:关键字,称为XSS Filter。
javascript script base等
可以在网上找到很多关于XSS Filter的实现。
但是如果用户提交的是变量$var
,就不会被过滤。但是var
的内容却携带有XSS攻击脚本的话,一样会被攻击成功。
在对特殊字符处理的时候,还需要注意不要把正常的业务影响到。比如:
1+1 < 3
还有下面的情况
$nickname='hello "world"'
如果在XSS Filter中对双引号进行转义:
$nickname='hello "world"'
在JavaScript代码中展示时:
<script>
var nickname='hello "world"';
document.write(nickname)
</script>
这两段代码,得到的结果并不一样。
hello "world"
hello "world"
而第一个结果并不是用户想看到的。
安全的编码函数
针对HTML代码的编码方式是HtmlEncode,它并非专有名词,只是一种函数实现,它的作用是将字符转换成HTMLEntities,对应的标准是ISO-8859-1。
针对PHP,有htmllentities,htmlspecialchars,相应的,JavaScript的编码方式可以使用JavaScriptEncode。
在对抗XSS时,JavaScriptEncode还要求输出的变量必须在引号内部,以避免造成安全问题。
var x = escapeJavaScript($evil);
var y = '"'+ escapeJavaScript($evil) +'"';
如果escapeJavaScript函数只转义了几个危险字符,比如' " < > & #
等,那么上面两行的代码输出后可能会变成:
var x = 1;alert(2);
var y = "1;alert(2)";
更严格的做法是,除了数字,字母外的所有字符,都使用十六进制'xHH'
的方式进行编码。
var x = 1;alert(2);
变成了
var x = 1x3balertx282x29;
这样,也可以最大化的保证代码是安全的。
还有其他很多类似于HtmlEncode、JavaScriptEncode功能的函数。可以在适当的情况下选用适当的函数。
XSS攻击主要发生在MVC架构中的View层,大部分XSS漏洞可以在模板系统中解决。
Secure By Default
XSS是很复杂的问题,需要”在正确的地方使用正确的编码方式“。
<body>
<a href=# onclick="alert('$var');">test</a>
</body>
如果用户输入
$var = htmlencode("');alert('2");
渲染后的结果是
<body>
<a href=# onclick="alert(''#x29;;alert('2');">test</a>
</body>
对于浏览器来说,htmlparse会优先于JavaScript Parse执行,所以解析过程是,被HtmlEncode的字符先被解码,然后执行JavaScript时间:
<body>
<a href=# onclick="alert('');alert('2')">test</a>
</body>
成功在onclick事件中注入了xss代码。
防止XSS攻击需要区分情况对待,并不是使用了某一策略就万事大吉。
处理富文本
用户发布文章、评论、图片等。
危险标签
<iframe> <script> <base> <form>等
过滤规则应该选用白名单,避免使用黑名单,比如,只允许
<a> <img> <div>等
白名单原则不仅仅用于标签的选择,同样应该用于属性与事件的选择。
CSS处理
如果允许用户自定义CSS、style,则也可能导致XSS攻击。那么需要一个CSS Parser对样式进行分析。
DOM型
<script>
function test(){
var str = document.getElementById("test").value;
document.getElementById("t").innerHTML = "<a href='"+str"'">testLink</a>
}
</script>
<div id="t"></div>
<input type="test" id="test" value=""/>
<input type="button" id="s" value="write" onclick="test()"/>
在button的onclick事件中,执行了test函数,而该函数中最关键的一句是:
document.getElementById("t").innerHTML = "<a href='"+str"'">testLink</a>
将HTML代码写入了DOM节点,导致漏洞产生。
即使通过JavaScriptEscape,也仍然可能产生漏洞。
<script>
var x="$var"
document.write("<a href='"+x+"'">testLink</a>)
</script>
<script>
var x="x20x27onclickx3dalertx28x29x3bx2fx27"
document.write("<a href='"+x+"'">testLink</a>)
</script>
在第一次执行JavaScriptEscape之后,只保护了变量x
,但是当document.write输出数据到HTML页面时,浏览器重新渲染了页面。在<script>
标签执行时,已经对变量进行了解码,其后document.write再运行时,参数就变成了
<a href=' ' onclick=alert(1);//''>testLink</a>
即使改成HtmlEncode依然可能产生漏洞
<script>
var x="1");alert(2);/""
document.write("<a href=# onclick='alert(""+x+"")'>testLink</a>)
</script>
服务器把变量HtmlEncode后再输出到<script>
中,然后变量x
作为onclick事件的一个函数参数被document.write到了HTML页面里。onclick事件执行了两次alert,第二次是被XSS注入的。
其他有可能导致XSS攻击的函数
.after()
.append()
.appendTo()
.before()
.html()
.insertAfter()
.insertBefore()
.prepend()
.prependTo()
.replaceAll()
.replaceWith()
.unwrap()
.wrap()
.wrapAll()
.wrapInner()
.prepend()
其他输入来源
document.URL *
document.location.pathname *
document.location.href *
document.location.search *
document.location.hash
document.referrer *
window.name
document.cookie
window.location(href hash等)
以及所有input框,都是极有可能产生XSS攻击的点。