本文主要涉及内容:
什么是XSS
跨网站脚本(Cross-sitescripting,通常简称为XSS或跨站脚本或跨站脚本攻击)是一种网站应用程序的安全漏洞攻击,是代码注入的一种。它允许恶意用户将代码注入到网页上,其他用户在观看网页时就会受到影响。这类攻击通常包含了HTML以及用户端脚本语言。
XSS攻击通常指的是通过利用网页开发时留下的漏洞,通过巧妙的方法注入恶意指令代码到网页,使用户加载并执行攻击者恶意制造的网页程序。这些恶意网页程序通常是JavaScript,但实际上也可以包括Java, VBScript, ActiveX, Flash 或者甚至是普通的HTML。攻击成功后,攻击者可能得到包括但不限于更高的权限(如执行一些操作)、私密网页内容、会话和cookie等各种内容。
XSS攻击手段和目的
攻击者使被攻击者在浏览器中执行脚本后,如果需要收集来自被攻击者的数据(如cookie或其他敏感信息),可以自行架设一个网站,让被攻击者通过JavaScript等方式把收集好的数据作为参数提交,随后以数据库等形式记录在攻击者自己的服务器上。
常用的XSS攻击手段和目的有:
预防手段【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页面,于此同时传入诸如到用户名字段中。
就像你上面看到的那样,脚本被恶意用户注入并在信任的用户浏览器中被执行。
下面一节,我们将通过一个正式的过程来识别或减轻这些问题。
注意:在XSS载体已经实施后之后,发现这些问题将会变得很快且很有价值。但如果有一种方式在软件开发的生命周期内致力于在任何代码执行或资源提交之前做早期预测以及历届应用程序的威胁,这样的代价岂不是非常巨大?是的,而且这是一个过程,我们在这里使用微软IT所谓的“威胁建模”来称呼它。
保护你的应用
为了保护ContosoBookmark Page应用免受攻击,我们首先需要理解恶意用户能够使用哪些手段来进行这样的攻击。一种不错的想法是,我们应该在设计的时候就应该留意它,使用威胁建模以及一个诸如TAM的工具。我们在应用程序已经被部署之后,使用如下步骤来处理:
在这一节,我们将使用示例应用来贯穿这些步骤,然后看看我们应该怎样使用微软的Anti-Cross Site Scripting类库 V1.5来避免用户遭受XSS攻击。
步骤一:审查asp.net生成输出的代码
记住,为了完成一次成功得XSS攻击,恶意用户必须找到一种方式在应用程序的输出数据中嵌入他们的某些恶意输入。因此,我们需要识别出应用程序中产生输出的代码。这通常不是一件非常简单的任务,特别对那些大型项目而言,并且有些输出可能确实不必要进行编码。这些情况下,下面的表格可以帮助你处理这些大量数据:
用例场景 |
场景输入 |
输入可信? |
场景输出 |
输出中包含不可信的输入? |
需要编码? |
使用编码方法 |
Yes/no |
Yes/no |
Yes/no |
为了正确使用该表格,我们首先要知道我们的应用是干嘛的。表格中的一些项我们可以立即填写:
注意:如果你不确信输入是否可信,宁可谨慎一点,假设他们是不可信的。不可信的输入包括:
应用程序级别的全局变量
基于我们的示例项目,这里我们对该表格可以这样填写:
用例场景 |
场景输入 |
输入可信? |
场景输出 |
输出中包含不可信的输入? |
需要编码? |
使用编码方法 |
用户添加书签 |
用户名、描述、书签 |
no |
写入文件的书签实体 |
|||
应用程序“答谢”用户 |
用户名称 |
No |
感谢信息页面 |
这时,当我们客观地填写了该表格,我们就可以很直观地看出,代码中有哪些是完成输出的:
步骤二:决定是否输出中包含不可信的输入
在该步骤中,我们的目标是确定,是否在上一步筛选的输出中是否包含有任何不可信的用户输入。基于输入和输出场景,现在我们的表格看起来就像如下这样:
用例场景 |
场景输入 |
输入可信? |
场景输出 |
输出中包含不可信的输入? |
需要编码? |
使用编码方法 |
用户添加书签 |
用户名、描述、书签 |
no |
写入文件的书签实体 |
Yes |
||
应用程序“答谢”用户 |
用户名称 |
No |
感谢信息页面 |
yes |
注意:如果你不确定输出中是否包含不确定的输入,保险点,假设他们都是不可信的。
步骤三:决定是否使用编码函数
在该步骤,我们的目标是理解我们需要采用哪个编码方法来编码我们的响应数据。如果在表格中下面的条件完全满足,那么输出就有编码的必要:
用例场景 |
场景输入 |
输入可信? |
场景输出 |
输出中包含不可信的输入? |
需要编码? |
使用编码方法 |
用户添加书签 |
用户名、描述、书签 |
no |
写入文件的书签实体 |
Yes |
No(输出被写入文件而不是web响应的数据) |
|
应用程序“答谢”用户 |
用户名称 |
No |
感谢信息页面 |
yes |
yes |
最终,我们需要决定使用哪个编码函数。接下来的表格将帮助你决定使用哪个编码函数:
编码函数 |
应该使用的场景 |
示例/模式 |
HtmlEncode |
不可信的输入被用作html输出,被分配给一个html属性除外 |
|
HtmlAttributeEncode |
不可信的输入作为一个html属性 |
|
JavaScriptEncode |
不可信的输入作为一个javascript上下文 |
… [Untrusted input] … |
UrlEncode |
不可信的输入作为一个url(例如作为一个查询参数的值) |
|
VisualBasicScriptEncode |
不可信的输入作为一个visual basic上下文 |
… [Untrusted input] … |
XmlEncode |
不可信的输入作为一个xml输出,除了把它作为一个xml节点的属性 |
|
XmlAttributeEncode |
不可信的输入作为一个xml的属性 |
|
我们最终的表格看起来变成下面的样子:
用例场景 |
场景输入 |
输入可信? |
场景输出 |
输出中包含不可信的输入? |
需要编码? |
使用编码方法 |
用户添加书签 |
用户名、描述、书签 |
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 = AntiXss.HtmlEncode(Request.QueryString["Name"]);
4、重新编译web应用
现在任何企图通过注入脚本到Name查询字符串字段的方式将会失败,因为不信任的数据以及被AntiXss.HtmlEncode方法嵌入到一个不可知性的表单中去了。
注意:一个通常的错误是编码不止一次是错误的。这经常会导致输入显示得不正确。例如,一个Hello Microsoft!的输入,被传入Microsoft.Security.Application.AntiXss.HtmlEncode方法中两次,将会导致浏览器打印出HelloMicrosoft!记住,你只需对不可信的输入编码一次即可。
深度剖析
为了使恶意用户的攻击变得更加困难,这里有一个定义能够防止更深度的XSS恶意攻击。
另外的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总结
可见XSS攻击的方式其实还是很多的,让你防不慎防。但是,有时你会发现他们的某些共性——注入再利用浏览器自动执行。所以,你必须在不可信的输入与输出上严格把关!
参考与引用:
酷壳:新浪微博的XSS攻击
MSDN