13.2 跨域捕获数据

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

实际上,在某些情况下,有各种攻击技巧可用于从其他域中捕获整个或部分响应。通常,这些攻击会对目标应用程序某方面的功能及常见浏览器的某个功能加以综合利用,从而突破同源策略防御,实现跨域捕获数据的目的。

13.2.1 通过注入HTML捕获数据

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

在这些情况下,就可以利用HTML注入条件向攻击者所在的域发送页面中的敏感数据。例如,在Web邮件应用程序中,攻击者或许可以捕获私人电子邮件的内容。或者,攻击者也许可以读取页面中使用的反CSRF令牌,从而实施CSRF攻击,将用户的电子邮件转发到任意地址。

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

img400

img401a

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

img401b

这段HTML将打开一个指向攻击者域中的URL的图像标签。该URL包含在单引号内,但URL字符串并未终止,<img>标签也没有结束。这会导致浏览器将注入点之后的文本视为URL的一部分,直到遇到单引号,也就是响应中随后出现引用的JavaScript字符串的位置。浏览器接受各种插入字符,也允许URL跨越多行。

用户的浏览器处理攻击者注入的响应时,它会尝试提取指定的图像,并向以下URL提出请求,从而向攻击者的域中发送敏感的反CSRF令牌:

img401c

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

img401d

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

img401e

由于上述第二个攻击仅注入了格式正常的HTML,因此能够更有效地避开那些旨在允许回显的输入中的HTML子集的过滤。但是这种攻击也需要用户干预,在某些情况下,这可能会降低它的效率。

13.2.2 通过注入CSS捕获数据

在上一节的示例中,攻击者需要在注入的文本中使用有限的HTML标记,才能跨域捕获部分响应。但是,许多时候,应用程序会阻止或对注入的输入中的<和>字符进行HTML编码,防止攻击者插入任何新的HTML标签。Web应用程序中大多存在此类纯文本注入条件,并且人们通常认 为这种条件不会造成危险。

例如,在一个Web邮件应用程序中,攻击者可以通过电子邮件主题行在目标用户的响应中注入有限的文本。在这种情况下,攻击者可以通过在应用程序中注入CSS来跨域捕获敏感数据。

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

img402a

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

img402b

很明显,此响应中包含HTML。但奇怪的是,浏览器将该响应加载为CSS样式表,将正常处理其中包含的任何CSS定义。在这段代码中,注入的响应定义了CSS font-family属性,并将一个引用的字符串作为属性定义。攻击者注入的文本并未终止该字符串,因此,该字符串会一直持续到响应的剩余部分,包括包含敏感的反CSRF令牌的隐藏表单字段。(请注意,CSS定义不需要被引用。但是,如果没有引用CSS定义,它们可能会在下一个分号位置终止,而该分号可能出现在攻击者希望捕获的敏感数据之前。)

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

img402c

此页面包含来自Web邮件应用程序的表示为样式表的相关URL,并运行脚本来查询font-family属性,该属性已在Web邮件应用程序的响应中定义。然后,font-family属性的值,包括敏感的反CSRF令牌,将通过针对以下URL的、动态生成的请求传送到攻击者的服务器中:

img403a

此攻击可在当前版本的Internet Explorer上实施。为防止这种攻击,其他浏览器已修改了它们处理CSS的方式,将来IE也可能会这样做。

13.2.3 JavaScript劫持

JavaScript劫持提供了另一种跨域捕获数据的方法,从而将CSRF转换为一种有限的“双向”攻击。如第3章所述,同源策略允许一个域包含其他域的脚本代码,并且该代码可以在调用域、而不是发布域中运行。只要可执行的应用程序响应使用仅包含非敏感代码(可由任何应用程序用户访问的静态代码)的跨域脚本,这种规定就不会造成危险。但是,今天的许多应用程序都使用JavaScript来传输敏感数据,并且其传输方式并不受同源策略的限制。此外,随着浏览器技术的发展,许多语法都可以作为有效的JavaScript执行,这为跨域捕获数据提供了新的机会。

应用程序设计方面的变化(归于宽泛的“2.0”概念)也为使用JavaScript从服务器向客户端传输敏感数据提供了新的方法。许多时候,要通过向服务器提供异步请求更新用户界面,一种快速有效的方法,是动态插入脚本代码,并在其中以某种形式包含需要显示的特定的用户数据。

在这一节中,我们将介绍各种使用动态执行的脚本代码来传输敏感数据的方法。同时,我们还将说明如何劫持这类代码,以捕获其他域中的数据。

1.函数回调

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

img403b

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

img403c

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

img404a

如果用户在访问攻击者的页面的同时,还登录了某个易受攻击的应用程序,则攻击者的页面将动态插入包含用户个人信息的脚本。该脚本将调用showUserInfo函数,由攻击者实施时,它将接收用户的个人资料,包括用户的密码(如本例所示)。