作者: Nick Sullivan (CloudFlare, 2016年1月21日);译者: Google Translate, Tao Wan (Huawei Canada,2016年2月4日)
Web是一个协作的生态系统。 Web标准的存在,保证了网络的参与者以可预见的方式行事。如果网络参与者偏离了既定标准,就会发生意想不到的结果。本文描述的就是这样一个意想不到的结果。
最近一组研究人员发表在NDSS 2016 的一篇论文 “Forwarding Loop Attacks in the Content Delivery Networks“ (针对内容分发网络的转发环路攻击)[1],描述了Web服务如果以不兼容的方式进行交互时会发生什么。他们描述的攻击,恶意用户可以让多个服务提供商相互发送其请求,从而导致无休止的循环。这样的请求循环可以导致服务供应商的资源枯竭和服务拒绝。该论文还展示了,转发环路攻击对大批的CDN是可行的。
针对上述论文提到的攻击,我们已经对CloudFlare的服务做了相应的修改,使之符合于HTTP代理的相关标准。然而要彻底避免上述攻击,所有的代理服务必须都遵循相关标准。如果有一个服务供应商不遵循标准,其它所有遵循标准的服务商,仍然可以被攻击。在这篇文章中,我们将介绍这种新型的攻击,并说明,一个供应商如何从问题的一部分,变成解决方案的一部分。
反向代理
CloudFlare 是使用反向代理来工作的。当HTTP(S)请求进入CloudFlare的网络,会发生下面的两种情况之一; 1)CloudFlare返回缓存的响应;2) CloudFlare向原始网站发出请求,并转发原始网站返回的相应。CloudFlare可以检查和修改通过其网络的请求,这个能力使得许多强大的功能成为可能,例如高速缓存、WAF(Web应用防火墙)、RocketLoader等等。
另外,在一个网站的前面使用多个反向代理也并不少见。这种做法称为堆叠代理(Stacking proxies),通常被用来提供多个不同的服务特性。例如,你可以CloudFlare进行缓存,但使用另外一个服务商的WAF。虽然我们更希望客户使用CloudFlare提供的先进的WAF,但使用其它的WAF也是合理的,而且我们的很多客户也是这么做的。多个代理可以在原始服务器的前面被堆叠,但是,如果最后一个代理指向了第一个代理会发生什么?你将得到一个代理循环。
两个代理形成的循环很容易理解。配置第一个反向代理使用第二反向代理作为源网站,同时配置第二个反向代理使用第一个作为它的源网站。
从理论上说,发给该网站的任何请求最终会在两个代理之间被来回发送。每次循环都将导致一个请求被发送,并消耗资源。幸运的是,大多数反向代理都有保护,可以避免这样的简单攻击。
防止简单的循环
HTTP 1.1的作者意识到请求循环的可能性,并在制定标准时,定义了相应的保护。这个环路保护是通过 “Via” 报头来实现的。下面的段落来自 RFC 7230的5.7.1部分:
————————————————————————————————————–
“Via”头字段,表示在用户代理和服务器之间(请求方向),或者在原始服务器和客户端之间(响应方向),存在中间协议和接收者。这类似于电子邮件的“Received”头字段(RFC5322 的3.6.7)。“Via”头字段可以用来向前追踪消息,从而避免请求循环,并发现请求/响应链中发件者的协议功能。
…
一个“Via”头字段的多个域值可以被用来表示单个代理或网关。每一个中间人都追加自己的信息,来表述如何接收到该消息,最终结果是,所有转发代理形成了一个排序。一个代理在转发每个消息时, 必须按照以下要求,添加相应的 “Via头字段。一个HTTP到HTTP的网关必须在每个入站请求消息中添加 ”Via“头字段,可以在转发的响应消息中添加”Via“头字段。
…
例如,一个请求消息可以从HTTP / 1.0的用户代理被发送到一个叫”fred”的内部代理,该内部代理使用HTTP / 1.1把请求转发到一个公共代理p.example.net,该公开代理则将请求转发到原始服务器www.example.com, 从而完成了该次请求。www.example.com接收到的请求将有以下的 Via头字段:
Via: 1.0 fred, 1.1 p.example.net
一个发送者,不应该合并”Via” 的多个条目,除非它们属于同一个组织,并且主机信息已经被匿名化了。如果”Via” 的多个条目包含了不同的协议值,则绝对不可以被合并。
————————————————– ——————————
CloudFlare目前使用了这一机制,以防止请求循环。当一个请求通过CloudFlare的网络时,并且不在缓存中,CloudFlare将创建一个新的请求,发给原始网站。CloudFlare发出请求的”Via” 头字段中, 包含从上一个节点收到请求的HTTP 协议版本,和一个CloudFlare专用值:
Via:1.1 CloudFlare
如果一个请求进入“CloudFlare”网络时,其Via头字段里包含了”cloudflare”这个值,则会返回错误。这可以避免在CloudFlare网络中形成请求循环。
实施这种保护手段,就可以保证CloudFlare不会受到HTTP请求循环的攻击吗?请不要过快地下结论。
坏消息
并不是所有的反向代理服务都遵循RFC 7230标准。一些代理服务给客户提供过滤或修改HTTP头的能力,包括“Via”头。这其实是RFC不允许的:代理有义务保留其它代理添加的“Via”头字段里的标签。代理只允许修改其自身组织添加的头部分。允许代理修改其它代理添加的“Via”头字段,会导致坏事的发生。
我们用上面的两个代理回路的例子来解释。假设两个代理服务器在发送请求时,都会添加自己的的Via头,并在收到带有自己“Via”头的请求时,返回错误。假设第二个代理会把接收到的请求里的“Via”头过滤掉。当请求从第二代理返回时,第一个代理已经无法确认它已经转发过该请求。然后,该请求会被当正常请求一样处理,被发送给第二个代理。第二个代理如果不做回路检查,则会继续将该请求发送回给第一个代理,如此循环往复。
这种攻击可以造成很大的伤害,可以耗尽两个服务提供商的资源。它还可能导致自动攻击防御系统的意外行为,从而进一步导致一个服务提供商被另外一个封锁。不用说,这是很理想的。
对于CloudFlare的客户
有一些Web服务器,如果收到的请求包含“Via”头字段,在缺省情况下,不会压缩返回的响应。这可以导致你的服务器在给CloudFlare发送数据时,浪费不必要的带宽。请咨询CloudFlare的知识库,来学习如何测试你的服务器是否有此行为,以及如何将其禁用。如果你不知道如何修改你服务器的配置,请联系CloudFlare的技术支持。
呼吁采取行动
上述NDSS论文的作者们,在论文发布之前,联系受影响的CDN厂家,但可能不是所有的厂家都已经修复了。如果您的组织向公众提供反向代理服务,我们建议您实现以下逻辑:
●在任何情况下,都不要让客户删除或修改到达他们网站的请求里的“Via”头字段。
●进行代理时,追加符合RFC 7230标准的 “Via”头字段。
●如果一个请求包含你自己的“Via”头字段,请返回相应的错误。
一个不符合标准的反向代理服务可能会给大家导致不良后果,让我们一起努力,以避免请求循环。
我要感谢万涛,陈建军,江健,梁锦津与我们一起,探讨了修复方案。我也想特别感谢Pasha Kravtsov 帮助调查了这个问题,感谢Rajeev Sharma帮助实施了基于“Via”头的解决方案。
参考文献:
[1] Jianjun Chen, Jian Jiang, Xiaofeng Zheng, Haixin Duan, Jinjin Liang, Tao Wan, Kang Li, Vern Paxson, Forwarding-Loop Attacks in Content Delivery Networks, accepted by NDSS 2016 。NDSS是国际网络安全四大会议之一,本文获NDSS 2016年杰出论文(Distinguished Paper)。
[2]论文下载:http://netsec.ccert.edu.cn/duanhx/files/2010/12/cdn_loop-final-camera-ready.pdf
[3]原文地址: https://blog.cloudflare.com/preventing-malicious-request-loops/