http://mdsec.net/auth/398/
不要犯下错误,依靠HTTP Referer消息头来指示请求是源自站内还是站外。Referer消息头可以使用旧版Flash进行修改,或用元刷新标签(meta refresh tag)来伪装。通常而言,使用Referer消息头并不能为Web应用程序提供强大的安全防御。
人们常称,如果应用程序中包含任何XSS漏洞,那么反CSRF防御机制就可以被突破。这种说法并不完全正确。但是,支持这种观点的思考方法是正确的;因为XSS有效载荷在本站执行,可以与应用程序进行双向交互,所以它们能够从应用程序的响应中获取令牌,并在随后的请求中提交这些令牌。
然而,如果某个本身受到反CSRF防御机制保护的页面也包含反射型XSS漏洞,那么这种漏洞并不能直接用于突破防御。记住,在反射型XSS攻击中,最初的请求为跨站点请求。这时,攻击者会设计一个URL或一个POST请求,其中包含随后被复制到应用程序的响应中的恶意输入。但是,如果易受攻击的页面实施了反CSRF防御,那么攻击者要想实施有效攻击,其专门设计的请求中必须已经包含必要的令牌。如果其中没有所需令牌,应用程序将会拒绝攻击者提出的请求,同时包含反射型XSS漏洞的代码路径也不会执行。这时,问题并不在于注入的脚本是否能够读取应用程序响应中的任何令牌(当然它能),而在于如何首先将脚本注入到某个包含那些令牌的响应中。
通常,在下面几种情况下,我们可以利用XSS漏洞突破反CSRF防御。
如果受保护的功能中存在任何XSS漏洞,那么攻击者总可以利用这些漏洞突破反CSRF防御。通过保存型攻击注入的JavaScript可直接读取脚本所在的应用程序响应中的令牌。
如果应用程序仅对一部分通过验证的功能实施反CSRF防御,并且某项未防御CSRF的功能中存在一个反射型XSS漏洞,那么攻击者就可以利用这个漏洞来突破反CSRF防御。例如,如果应用程序仅采用反CSRF令牌保护转账功能的第二个步骤,那么攻击者就可以利用反射型XSS攻击从其他步骤中突破防御。通过这个漏洞注入的一段脚本可以向第一个转账步骤提出一个站内请求,截取令牌,然后使用这个令牌进入第二个步骤。攻击之所以能够成功,是因为第一个没有采取CSRF防御的转账步骤返回了访问受保护页面所需的令牌。仅依赖HTTP cookie实现第一个步骤,意味着攻击者可以利用它访问保护第二个步骤的令牌,从而实施有效攻击。
在某些应用程序中,反CSRF令牌仅与当前用户相关联,而不是与用户的会话相关联。在这种情况下,如果登录表单未防范CSRF攻击,则应用程序仍有可能受到多阶段攻击。首先,攻击者使用自己的账户登录,获得一个与他的用户身份关联的有效反CSRF令牌。然后,攻击者对登录表单发动CSRF攻击,迫使受害用户使用他的证书登录,如上文介绍利用相同用户的保存型XSS漏洞时所述。一旦用户作为攻击者登录,攻击者将使用CSRF使用户提出相关请求,对XSS漏洞加以利用,同时使用他此前获得的反CSRF令牌。然后,攻击者的XSS有效载荷将在用户的浏览器中执行。由于用户仍然作为攻击者登录,XSS有效载荷可能需要使用户注销,然后诱使用户再次登录,最终,用户的登录证书和生成的应用程序会话都被完全攻破。
如果反CSRF令牌未与用户关联,而是与当前会话关联,且攻击者可以通过某种方法在用户的浏览器中注入cookie,则只需对以上攻击稍作修改即可(本章后面部分将介绍这种攻击)。这时,攻击者不是使用自己的证书针对登录表单实施CSRF攻击,而可以直接向用
户传送他当前的会话令牌及与该会话关联的反CSRF令牌。然后,该攻击的剩余部分与之前所述的步骤相同。
除这些情形外,在许多时候,针对CSRF攻击的有效防御能够在很大程度上阻止(即使不能完全阻止)攻击者利用某些反射型XSS漏洞。但是,在任何情况下,无论我们采取了何种反CSRF防御来阻止攻击者试图利用XSS条件,我们都应始终修复应用程序中存在的任何这类XSS条件。
基本上,与页面中的令牌有关的反CSRF防御旨在确保请求是由应用程序中的用户操作本身提出的,而不是由某个第三方域诱发的。即使采用了反CSRF令牌,第三方站点仍然可以通过UI伪装攻击诱使其他域中的用户执行操作。在某种程度上,这类攻击之所以能够成功,是因为生成的请求实际上来自攻击者针对的应用程序。UI伪装技巧通常也称为“点击劫持”(clickjacking)、“键击劫持”(strokejacking)等其他常见说法。
基本上,在UI伪装攻击中,攻击者的网页会将目标应用程序加载到其页面上的iframe中。而实际上,攻击者会用其他界面覆盖目标应用程序的界面。攻击者的界面中包含吸引用户并诱使其执行各种操作(如在页面的特定区域单击鼠标)的内容。用户执行这些操作时,虽然看起来其单击的是攻击者的界面中显示的按钮和其他UI元素,但他实际上是在不知情的情况下与攻击者所针对的应用程序进行交互。
以一个分两步进行转账的银行功能为例。在第一步中,用户提交转账信息。对此请求的响应将显示这些信息,以及一个用于确认该操作并进行转账的按钮。此外,为防止CSRF攻击,响应中的表单还包含一个隐藏字段,其中提供了一个无法预测的令牌。此令牌在用户单击“确认”时提交,应用程序将在转账之前验证它的值。
在UI伪装攻击中,攻击者的页面在此过程中使用传统的CSRF提交第一个请求。提交过程在攻击者页面内的iframe中完成。和正常情况下一样,应用程序会作出响应,返回要添加的用户的详细信息,以及一个用于确认该操作的按钮。此响应将在攻击者的iframe中“显示”,该iframe已由攻击者的界面覆盖,该界面旨在诱使受害用户单击包含“确认”按钮的区域。如果用户在此区域单击,他将在不知情的情况下单击目标应用程序中的“确认”按钮,从而创建新用户。这种基本的攻击如图13-1所示。
这种攻击之所以能够在纯粹的CSRF攻击无法奏效的情况下取得成功,是因为应用程序使用的反CSRF令牌以正常方式得到处理。虽然由于同源策略的原因,攻击者的页面无法读取该令牌的值,但攻击者的iframe中的表单包含了由应用程序生成的令牌,在受害用户不知情的情况下单击“确认”按钮时,这个令牌被返交给应用程序。在目标应用程序看来,一切都很正常。
要实施欺骗,即让受害用户虽然看到一个界面,但实际上却与另一个界面交互,攻击者可以采用各种CSS技术。加载目标应用程序的iframe可以为任意大小,位于攻击者页面中的任何位置,并显示目标页面的任意位置。使用适当的样式属性,可以令该iframe变得完全透明,从而使其对用户不可见。