本文的上篇中,我们着重介绍了跨站请求伪造的原理,并指出现有的安全模型并不能真正防御这种攻击。在下篇中,我们将向读者介绍在一些大型站点上发现 的几个严重的CSRF漏洞,攻击者利用这些漏洞不仅能够采集用户的电子邮件地址,侵犯用户隐私并操控用户帐户。如果金融站点出现了跨站请求伪造漏洞的话, 这些漏洞甚至允许攻击者从用户的银行帐户中划走资金。为了全面的防御CSRF攻击,建议对服务器端进行改造。此外,本文还会介绍服务器端解决方案应具备的 特征,如果缺乏这些特性,就会导致CSRF保护措施不必要地妨碍典型的web浏览活动。除此之外,本文还将介绍一个客户端浏览器插件,有了该插件的保护, 即使站点自身没有保护措施的情况下,用户也能免受某些类型的CSRF攻击的滋扰。跨站请求伪造是一种严重的Web漏洞,希望大家能提高对CSRF攻击的防 范意识。
下面是安全人员于今年在现实世界中NYTimes.com、Metafilter 和YouTube曾经出现过的跨站请求伪造漏洞。
一、纽约时报网站上的跨站请求伪造漏洞
今年,安全人员曾在NYTimes.com上发现了一个CSRF弱点,它使得攻击者可以获取用户的电子邮件地址。如果您是NYTimes.com的会员,那么任何站点都能利用该漏洞来获取您的电子邮件地址,并以您的名义来发送垃圾邮件。
这个攻击充分地利用了NYTimes.com的“Email This”功能,它允许用户将一篇NYTimes.com文章的链接发送给用户指定的收信人的电子邮件地址,如果需要的话,同时可以附带个人消息。收信人将收到一封类似下面的电子邮件:
This page was sent to you by: [USER’S EMAIL ADDRESS] |
要 想利用该漏洞,攻击者需要设法让已登录用户的浏览器向NYTimes.com的“Email this”页面发送一个请求。由于接收“Email this”请求的页面没有对CSRF攻击采取有效措施,所以只要设法让用户的浏览器向NYTimes.com发送一个精心构造的请求,就会导致 NYTimes.com发送一封电子邮件到攻击者所指定的地址。如果攻击者把收信人电子邮件地址指定为他自己的电子邮件地址,他将收到一封来自 NYTimes.com电子邮件,当然其中必定含有某用户的电子邮件地址。
这个弱点的利用方法很简单。NYTimes.com上的每篇文章 都有一个指向“Email this”页面的链接,而“Email this”页面含有一个表单,用户可以在其中输入一个收信人的电子邮件地址。这个表单还包含一些隐形的变量,这些变量随文章的不同而不同,所以这些隐形的 变量具有唯一性。下面是表单示例:
{form |
因 为NYTimes.com没有区分GET和POST请求,所以攻击者可以把该表单转换成一个GET请求(这样就可以将来将其用于{mg}签中)。 把表单转换成一个GET请求时,需要将每个参数附加到URL的查询字符串上(形式为NAME = VALUE,并用&号分隔)。
一旦攻击者构造好URL,他就可以把它设为{img}标签的SRC属性。如果某个NYTimes.com的已登录用户访问了任何包含上述标 签的页面,那么浏览器就会用攻击者的参数来加载“Email this”页面,并引起NYTimes.com发送一封包含该用户的电子邮件地址的电子邮件给攻击者。攻击者可以存储这个电子邮件地址,以供将来之用(例 如用于发送垃圾邮件)或者使用该电子邮件地址来识别他自己的站点的访客的身份。这可以引起严重的隐私泄漏,例如某些颇具争议的站点(例如政治的或者非法的 站点)的管理员识别他们的用户的身份。
安全研究人员用Firefox、Opera 和Safari 等对该攻击进行了验证。由于P3P的原因,它对Internet Explorer无效。后来纽约时报将页面改成只允许POST请求,所以现在能够防止原来的攻击。
二、MetaFilter 网站的跨站请求伪造漏洞
同 样是在今年,安全研究人员在MetaFilter发现了一个CSRF弱点,它允许攻击者劫持用户的帐户。MetaFilter有一个“Lost Password”页面,该页面允许用户请求他的口令。在该页面中输入一个用户名,MetaFilter就会把该用户的当前口令通过电子邮件发至该用户相 应的邮件地址。这意味着,攻击者只要能够改变一个用户的电子邮件地址,他就能够利用“Lost Password”页面来接受该用户的口令,继而利用该口令来控制该用户的帐户。
研究人员发现的CSRF攻击允许攻击者改变一个用户的电子 邮件地址。为了利用这个攻击,攻击者需要设法让用户的浏览器发送一个请求到更新用户概况的 页面。这个页面将用户的电子邮件地址作为一位参数接收,所以,攻击者可以把传递给该页面的电子邮件地址换成他自己的地址。下面提供一个嵌入在一个页面中的 HTML来演示这个攻击过程:
{mg src="http://metafilter.com/contribute/customize_action.cfm?user_email=[ATTACKER’S EMAIL]"/} |
虽 然这会改变任何已登录用户的电子邮件地址,但是攻击者不会知道到底修改了哪些用户的帐户。但是,攻击者可以通过利用MetaFilter的另一项 功能来达到此目的,该功能使用户能将其他用户标记为“contacts”(即联系人)。 攻击者可以通过类似于像上面介绍的CSRF来设法让用户在不知不觉中将攻击者添加到他的联系人名单中。
研究人员用Firefox对该攻击进行了验证。不过由于P3P的原因,无法用Internet Explorer进行此项测试。
三、YouTube网站的跨站请求伪造漏洞
安 全研究人员发现,在YouTube上几乎所有用户可以执行的动作都具有CSRF漏洞。如果攻击者已经将视频添加到用户的“Favorites”, 那么他就能将他自己添加到用户的“Friend”或者“Family”列表,以用户的身份发送任意的消息,将视频标记为不宜的,自动通过用户的联系人来共 享一个视频,为用户预订一个“channel”(一组由某个人或组提供的视频),将视频添加到用户的“QuickList”(一组用户打算将来观看的视 频)。例如,要把视频添加到用户的
“Favorites”,攻击者只需在任何站点上嵌入如下所示的{mg}签:
{mg src="http://youtube.com/watch_ajax?action_add_favorite_playlist=1&video_ |
攻击者也许已经利用了该漏洞来提高视频的流行度。例如,将一个视频添加到足够多用户的“Favorites”,YouTube就会 把该视频作为 “Top Favorites”(一组被大量收藏的视频)来显示。除提高一个视频的流行度之外,攻击者还可以导致用户在毫不知情的情况下将一个视频标记为“不宜 的”,从而导致YouTube删除该视频。
这些攻击还可能已被用于侵犯用户隐私。YouTube允许用户只让朋友或亲属观看某些视频。这些攻击会导致攻击者将其添加为一个用户的“Friend”或“Family”列表,这样他们就能够访问所有原本只限于好友和亲属表中的用户观看的私人的视频。
攻 击者还可以通过用户的所有联系人名单(“Friends”、“Family”等等)来共享一个视频。“共享”就意味着发送一个视频的连接给他们, 当然还可以选择附加消息。这个消息可以包含一个连接,这就是说攻击者可以强迫用户包含一个具有攻击性的网站的链接。收到该消息的用户可能单击这个连接,这 使得该攻击能够进行病毒式的传播。研究人员用Firefox对此攻击进行了验证。但是对于Internet Explorer来说,由于P3P的原因,无法用它对此漏洞进行攻击。
四、保护措施概述
上 面讲述了现实世界中发现的一些跨站请求伪造漏洞。下面介绍如何从服务器端和客户端来防御这种攻击。目前,已有两个工具来保护大量用户免遭CSRF 攻击。第一个工具是一个服务器端工具,它能全面保护一个潜在的目标站点免受CSRF攻击。第二工具是一个客户端工具,它可以保护用户免遭某些类型的 CSRF攻击。表 1详细描述这两种技术的适用条件。我们还对服务器端解决方案应具备的特性进行了描述,具备这些特性的解决方案比之前倡议的解决方案更具优势,因为他们无需 服务器状态,并且不会影响一般的web浏览活动。
目标服务器的安全措施 没有使用本文推荐Firefox插件的用户 使用本文推荐Firefox插件的用户
没有保护措施的目标服务器 | 不受保护 | 不受保护 |
仅仅接受POST请求的目标服务器 | 不受保护 | 受保护 |
使用服务器端保护措施的目标服务器 | 受保护 | 受保护 |
表1:用户保护情况对照表
这个表显示了在那些情况下受到或没有受到CSRF攻击保护。服务器端保护措施可以对站点的所有用户提供保护;而客户端浏览器插件可以在服务器要求使用POST请求时为用户提供保护。下面先介绍服务器端的保护措施。
五、服务器端保护措施
最 近,已经出现了许多简化web开发框架,这些框架支持不同的开发语言,例如Code Igniter(PHP),Ruby on Rails(Ruby ),django(Python),Catalyst(Perl)和Struts(Java)。这些框架的一个主要优点是可以直接将CSRF保护措施放到 框架中,这样开发人员就不必亲自实现保护措施了。在框架级别实现的CSRF保护措施常遭受更大的疏漏,但是由于粗心引起的bug或者CSRF误报更低。
个别站点和框架可以通过采取下列措施来保护他们自己免受CSRF攻击:
⒈ 只允许GET请求检索数据,但是不允许它修改服务器上的任何数据。
这个修改可以防止利用{img}标签或者其它的类型的GET请求的CSRF攻击。另外,这个建议遵循RFC 2616(HTTP/1.1):
具 体说来,按照约定,GET和HEAD方法不应该进行检索之外的动作。这些方法应该被认为是“安全的”。虽然这个保护措施无法阻止CSRF本身,因 为攻击者可以使用POST请求,但是它却可以与(2)结合来全面防止CSRF漏洞。这里,我们假定对手无法修改用户的cookie。
⒉ 要求所有POST请求都包含一个伪随机值。
当 用户访问站点时,该站点应该生成一个(密码上很强壮的)伪随机值,并在用户的计算机上将其设为cookie。站点应该要求每个表单都包含该伪随机 值(作为表单值和cookie值)。当一个POST请求被发给站点时,只有表单值和cookie值相同时,该请求才会被认为是有效的。
当攻 击者以一个用户的名义提交表单时,他只能修改该表单的值。攻击者不能读取任何发自该服务器的数据或者修改cookie值,这是同源策略的缘故。 这意味着,虽然攻击者可以用表单发送任何他想要的值,但是他却不能修改或者读取存储在该cookie中的值。因为cookie值和表单值必须是相同的,所 以除非攻击者能猜出该伪随机值,否则他就无法成功地提交表单。
3. 使用一个与会话无关的伪随机值。
与会话无关的伪随机值并不能防止在中所述的CSRF攻击。
这种服务器端保护形式具有下列特性:
轻量级。这个解决方案不要求服务器端的状态。站点唯一要做的是生成一个伪随机值(如果当前没有的话),并在一个POST请求到达时比较这两个值,所以这种CSRF保护措施只需很少的计算工作。
兼 容并行会话。如果用户在一个站点上同时打开了两个不同的表单,CSRF保护措施不应该影响到他对任何表单的提交。考虑一下如果每次表单被装入时站 点生成一个伪随机值来覆盖以前的伪随机值将会发生什么情况:用户只能成功地提交他最后打开的表单,因为所有其他的表单都含有非法的伪随机值。必须小心操作 以确保CSRF保护措施不会影响选项卡式的浏览或者利用多个浏览器窗口浏览一个站点。方法是,设立一个站点级别cookie,然后在一定时间内让所有表单 都使用该cookie。
对认证没有任何要求。这种解决方案不要求使用特定类型的认证。它能工作在通过cookie会话、HTTP认证、SSL认证或者IP地址对用户进行认证的站点上。
之前也有人提议在表单中使用伪随机值,不过许多提议的实现没有提供上述特性。例如,有的需要服务器状态,而有的会破坏项卡式的浏览。但是,之前提议的解决方案没有强调跟正常浏览行为相兼容的重要性。
任 何拦截POST请求并“包装”生成{form }标签的命令的框架都能够把以上所述CSRF保护措施透明地组合进该框架。例如,如果一个框架要求开发人员调用函数form_open (...)来生成一个{form ...}标签的话,那么就可以对这个框架加以修改,让它在每次创建一个表单的时候都自动地生成一个伪随机值:
{form ...} |
此 外,该框架还能处理跟cookie值有关的设置,并用该cookie值跟提交过来的值相比较。一个框架添加了这种CSRF保护措施,那么就能保护 该框架的所有用户免受CSRF攻击。 因为这种CSRF保护措施是轻量级的,并且对于框架或者开发人员提供的认证方法没有任何要求,所以强烈建议那些拦截POST请求并提供了生成{form} 标签的函数的框架都实现这种CSRF保护措施并将其设为默认保护措施。该框架还为开发人员提供了是否禁用该项保护措施的能力,例如他们已经单独地实现了 CSRF保护措施或者他们不想要cookie。
框架Code Igniter提供了这样的一个插件,该插件不要求开发人员对现有表单做任何修改,并且会对POST请求(并且对POST请求的伪随机值进行验证)和创建 {form}标签的函数调用进行拦截。该插件还提供了一个函数,该函数允许CSRF标志被添加到AJAX请求,尽管这要求开发人员的干预(Code Igniter没有提供执行AJAX请求的标准方式)。该插件的下载地址:http://www.cs.princeton.edu/˜wzeller/csrf/ci/。
六、客户端保护措施
由 于使攻击者成功地执行CSRF攻击的请求是由浏览器发出的,所以可以创建客户端工具来保护用户不受此种攻击。现有的工具RequestRodeo 通过在客户和服务器之间充当代理来防止CSRF攻击。如果RequestRodeo发现了一个它认为是非法的请求,它会从该请求剥离验证信息。虽然这种方 式在很多情况下都能有效,但是它具有一些局限性。具体地说,当客户端使用了SSL认证或者使用JavaScript生成部分页面(因为 RequestRodeo分析的是在浏览器显示之前的流经代理的那些数据)时,它就不起作用了。 人们已经开发了一个浏览器插件,不仅可以使用户可以免受某些类型的CSRF攻击,并且还能克服以上所述的局限性,这个工具是作为Firefox浏览器的扩 展实现的,其地址是http://www.cs.princeton.edu/˜wzeller/csrf/protector/。 为了有效地防范CSRF攻击,用户需要下载安装这个扩展。该扩展会拦截所有的HTTP请求,并判断是否允许该HTTP请求。这个判断要用到下列规则。首 先,POST请求之外的任何要求都是允许的。第二,如果发出请求的站点和目标站点符合同源策略的要求,那么该请求被允许。第三,如果发出请求的站点被允许 使用Adobe的跨域政策来建立一个请求的话,那么该请求也会被允许。如果我们的扩展拒绝一个请求,该扩展会通过一个常见的界面来提示用户(即 Firefox所使用的popup blocker)该请求已经被阻止,并且让用户选择是否将站点添加到一个白名单中。
该扩展仅仅拦截POST请求。这意味着,它无法保护用户免受使用GET请求的CSRF攻击 阻止这种类型的攻击的唯一方法是不允许任何跨域GET请求,或只允许用户一次只能登录到一个站点,但是这两个限制可能是用户无法忍受的。
七、小结
CSRF攻击在漏洞识别、利用和修补上相当简单,人们可以在几秒内分析站点,发动攻击也只需几分钟的时间。对于这些攻击的流行,最合理的解释是Web开发人员对于该问题的无知,以及误认为所实施的针对更为人们所熟悉的跨站脚本攻击的防范措施还能防止CSRF攻击。
我 们希望这里介绍的攻击足以显示CSRF攻击的危险性,并引起Web开发人员给予这些攻击足够的重视。建议框架的创建者为他们的框架添加CSRF保 护措施,从而保护建立在该框架之上的站点。在框架级别添加CSRF保护措施使得开发人员免于复制代码,甚至不用对CSRF攻击有深入的了解,当然最好对这 些攻击进行了解。当然,在所有的网站都对CSRF攻击采取防范措施以前,用户可以使用这里介绍的Firefox浏览器插件来设法保护他们自己,估计将来其 它浏览器也会出现类似的插件。