通过用户限制或如何创建漏洞提供安全性

在2019年,CDN网络上发现CPDoS缓存中毒(拒绝服务)漏洞,该漏洞使CDN提供者的HTTP缓存中毒并导致拒绝服务。该漏洞尚未引起大肆宣传,因为在实际攻击中还没有发现。但我想分别讨论一种缓存中毒方法。HTTP方法覆盖。


如果以一种或另一种方式利用漏洞的其他变体依赖中介程序的错误或请求修改功能,则“方法替代”变体基于同名策略,这不是HTTP标准的一部分,并伴随着其他问题,并且由于粗心而产生和传播与安全的关系。在这里,我们将考虑它。

如果您错过了CPDoS的简要介绍
, URI method .

, , , , - . — - - -, , - , . , .

, . , , -. - , , .


限制客户,可以的越少-破坏的越少


由于某些Web应用程序防火墙和HTTP客户端实现非常受限制,并且不允许执行除GET和POST之外的方法,因此非常需要在请求中重写该方法。问题不在于这是实施限制,而是由于安全策略对HTTP客户端的故意限制。

显然,一切都是出于良好目的而进行的,目的是切断拥塞的流量,这对于普通HTTP客户端而言是非标准的。但是为了追求安全性,除GET和POST之外的所有方法都被切断。也许是因为这些是通用服务器唯一非必需的方法

为何要求实行如此严格的限制尚不清楚。是的,为了迷惑解析器而引入各种字符的攻击仅仅是文本协议的爱好。但是您可以允许更多的方法,例如,至少采用标准本身描述的方法在IANA中注册的方法。完全删除方法检查是不值得的,但是您可以拨打许多最受欢迎的方法,并从中排除那些更改交互协议并中断代理服务器(CONNECT)上的工作的方法。但是,事实并非如此,这是一项安全策略,对客户引入了不必要的限制和禁止。

而且客户仅限于错误的客户。他们希望限制来自HTTP客户端的消息的可变性,并限制这些WAF保护的客户端,最终应用程序服务器及其开发人员。现在,开发人员只剩下两种方法,这些方法并不总是足以描述HTTP客户端的逻辑。

创造约束来克服它们。


可以预料,这种过多的限制迟早会开始干扰Web开发人员。具有讽刺意味的是,要摆脱这种WAF很容易。特别是当他们与客户或提供者在一起时。挑战他人的安全政策是灾难性的事情。

由于HTTP的灵活性,因此绕过此限制并不困难;只需在请求中添加一些内容即可覆盖该方法。严格的WAF将仅在请求行(请求的第一行)中检查该方法,并乐意在此查看批准的GET或POST。后端将能够解析添加的元素并从中提取实际方法。

你可以用谷歌搜索 一堆 文章, 实际上是 一堆有关不良代理如何破坏REST应用程序的信息,以及作者如何必须在单独的标头中传递真实方法。在所有这些建议中,他们建议您输入大致相同的标头(X-HTTP-Method,X-HTTP-Method-Override或X-Method-Override-拼写有所不同)以指示被覆盖的方法。很少,很少有人能找到可用于同一目的查询组件URI的引用。

这些文章缺少的是“安全注意事项”部分。他们就是。

方法重写安全吗?


有时,Web应用程序的开发人员会忘记客户端和服务器之间可能存在通过HTTP协议进行交互的中间参与者:代理,提供商的Web缓存,CDN和WAF。 TLS的普及极大地减少了客户端和服务器之间的中间参与者的机会。客户端和后端之间唯一的代理很可能是使用Nginx自己的服务器。这样的配置很容易在发行前在典型场景下进行测试。

但是,我们正进入CDN时代,越来越多的应用程序将隐藏在读取和操纵用户流量的CDN后面。直接后端几乎永远不会为用户服务,而隐藏在反向代理后面以提高响应速度和性能。因此,您将必须记住,重写方法如何影响中介服务器上的请求处理。

我想谈谈的攻击主要适用于HTTP / 1.1。HTTP / 2以某种方式继承了旧标准的行为,以某种方式继承了自己的方式,因此,将分别考虑每种攻击对新标准的适用性。

缓存攻击


大多数情况下,中间服务器不考虑方法重写,不检查X-HTTP-Method-Override系列的标头,并使用请求行中的主方法处理请求。而且,由于在缓存中搜索请求的方法(方法+ URI)中未包含覆盖的方法,因此此类服务器无法将POST与POST + X-HTTP-Method-Override:DELETE区分开。这意味着,如果后端可以监视和执行覆盖的方法则不能将任何请求缓存到某个URI。

CPDoS文档很好地说明了如果缓存这样的请求会发生什么情况。当攻击者将POST请求伪装为GET请求时,代理不会识别替代内容,并将该请求视为合法的GET请求。但是,后端识别覆盖的方法并执行X-HTTP-Method-Override-POST标头中描述的动词。由于未为目标URI定义POST方法,因此服务器会生成错误。此外,后端响应作为对原始方法GET的响应存储在缓存中。现在,对下一个URI的任何下一个GET请求都将返回一个缓存的错误。


实际上,攻击范围比文档中介绍的略宽。作者专注于将错误存储在缓存中,该错误并非在所有地方(已经)都可以再现。但是,如果定义了所选URI所请求的方法并将成功执行该方法,则代理将收到状态为200的响应并将其缓存。然后,相同URI的后续请求将收到对完全错误的方法的响应。在这种情况下,不再需要原始CPDoS描述中的4XX响应的缓存错误。

可能会出现相反的问题。如果一个受人尊敬的HTTP客户端发送了GET + X-HTTP-Method-Override:PATCH请求(这很糟糕,但是稍后会详细介绍),并且缓存已经具有GET响应,那么客户端将收到此缓存的响应。在这种情况下,后端将永远不会收到PATCH请求,这可能会违反客户端和服务器上的应用程序逻辑。

您可以通过建立正确的缓存策略并将资源分成两类来减少对缓存的影响:不接受或不需要方法重写操作的资源,可以对它们的响应进行缓存,以及必须进行方法重写操作的资源,这些答案的任何缓存都不可接受。但是缓存的资源越少,CDN的用途就越小,到达后端的流量越多,应用程序遭受HTTP泛洪的可能性就越大。

因此,最好尽可能多地使用HTTP缓存,为此,缓存服务器必须能够区分具有不同重写方法的请求。第一种方法是将查询组件的方法覆盖传递到URI:

POST /some-uri HTTP/1.1
X-HTTP-Method-Override: DELETE
   ↓  ↓   ↓
POST /some-uri?method=DELETE HTTP/1.1

现在,使用不同方法的请求在缓存中看起来有所不同,因为它们获得了不同的密钥。一些代理倾向于不将对包含查询组件的请求的响应缓存在URI中。但这只会影响缓存效率。此方法始终解决不正确的缓存问题。

另一种方法是将方法重写保留在单独的标头中,但输入辅助键以在缓存中找到答案。使用Vary标头可以做到这一点。在处理请求时,服务器将使用方法重写重复该标头,并在Vary标头中反映此标头的名称。然后,在以下请求中,当在缓存中搜索请求时,缓存服务器将使用重写方法的值作为辅助键。


如果中间服务器可以使用辅助密钥,则此方法有效。通常是这种情况,但是代理信任级别(会削减除GET和POST之外的所有方法)通常较低,因此最好进行检查。

通过请求主体内的任何实体覆盖方法与通过附加标头覆盖具有完全相同的缺点-它在缓存的可见性之外。

消息队列攻击


即使关闭了缓存攻击,也不是全部。攻击者通过重写方法可能会尝试更改响应的帧,从而违反其他客户端的请求-响应对的对应关系。或强制应用程序的服务器端多次处理相同的请求。

为此,最重要的是在反向代理模式下运行的中间服务器。也就是说,任何缓存或CDN服务器。这样的代理支持相对少量的与后端的连接,并且将来自每个客户端中许多客户端的请求相乘。这既需要承担支持从后端到代理服务器的大量客户端连接的负担,又需要平衡后端之间的负担。 TLS连接也会在代理上终止,客户端连接永远不会直接连接到后端。

由于现在来自不同客户端的请求将在后端和代理之间处于同一连接中,因此有必要在请求-响应对之间保持清晰的对应关系。大多数代理不进行管道传输(管道)对后端的请求,并在请求-响应模式下使用它。请求-响应模式更简单,并且实际上受到一种威胁-连接阻塞的威胁。如果使连接挂在一个请求-响应对上,则可能导致延迟甚至拒绝处理以下请求(例如,如果您成功溢出了代理请求队列)。

更有效率的代理将请求管道传输到后端-这使您可以立即将请求包发送到服务器,并等待它们的执行。性能更高,但是威胁更多。首先,行头阻塞的问题在任何地方都不会消失-即使后端可以取消请求的管道并并行执行它们,但如果它们中的第一个挂起,则无法发送请求。其次,如果您破坏了响应框架,则可以混淆代理并破坏请求-响应对的对应关系,那么某些客户端可以获取其他人的答案,或者至少可以实现与后端的即时连接关闭。


方法的最简单,最有趣的重新定义是用动词HEAD代替GET。如果第一个答案有一个主体,那么第二个则没有。此外,所有其他标头都相同,包括提供请求框架的标头。当代理将这样一个被覆盖的HEAD重定向到服务器时,它将不仅从服务器期望响应头,而且还从后端不希望发送的响应主体得到服务器的期望。如果代理和服务器以请求-响应模式进行交互,则连接将“挂起”,直到超时为止。

如果服务器发送以下答案(流水线模式),则可以将它们不解析为独立的答案,而可以解析为先前对GET的不完整响应的一部分。代理会将它们(或其中的一部分)放在“ GET”响应的正文中,并将其发送给攻击者以读取它们。您可以制作这样的伪GET来接收大文件并在代理和后端之间转储一些流量。成功与否取决于后端如何将Content-Length和Transfer-Encoding:分块的标头放置到帧消息中。第一个几乎总是允许您进行转储,第二个通常会产生解析错误并导致与后端断开连接。如果您根本不走运,那么伪GET可以完整涵盖几个答案,并在下一个答案之前结束。代理将完全无法识别此问题,并且在此连接中对于进一步的回答,将违反请求-响应对应关系。


即使通过重写该方法所实现的全部工作是关闭代理与后端之间的连接,这也足以构成攻击。您可以将服务请求与此类请求一起抛出-与后端的连接将不断断开。它们数量不多,并且重新发现需要花费时间,因此,可以大大降低代理后端通信性能,从而降低服务吞吐量。

自动垃圾邮件重播


上面我说过,来自尊敬的客户端的GET + X-HTTP-Method-Override:PATCH形式的请求是不好的。这很糟糕,因为方法具有两个属性:security幂等。安全性意味着该方法不会更改服务器的状态(只读),并且在本文中不会引起我们的兴趣。该方法的幂等性确保重复的请求与单个请求具有相同的效果。您可以类推:(a = 5)-幂等请求,以及(a += 2) -非幂等。

这个属性是我们感兴趣的。如果客户端和服务器之间的连接突然中断,则客户端知道该方法是幂等的,可以自动重新发送请求。代理的行为方式相同。非幂等请求不会自动重复,因为不知道它们如何影响服务器以及客户端最终将收到什么。我认为每个人都知道浏览器中的弹出窗口:“确定要重复请求吗?”

如果将非幂等方法屏蔽为幂等,则在发生错误的情况下不会将其丢弃,而是会再次重定向到服务器。即使客户端在重新提交请求之前考虑了真正的请求方法,这也无济于事,因为代理服务器不知道该方法的替代,并将重复此类请求。

如果攻击者能够强制后端与客户端之间断开连接,则攻击者可以使服务器多次执行非幂等请求,从而降低应用程序的可靠性和可预测性。在上一节中,我们只是找到了一种方法,该方法可以使用相同的方法覆盖来导致连接中断。尽管必须记住,按照定义,Internet是不可靠的网络,并且应用程序本身处于危险之中。

为了防止这种攻击,您应该仅使用不会将新属性作为传输添加到请求的方法。POST是一个不错的选择,因为默认情况下它既不安全也不幂等。

那个古老的HTTP / 1.1,和HTTP / 2一样?


HTTP / 2更改了在节点之间传输请求的方式,但未更改其词法含义。因此,在与请求值相关的那些攻击中,HTTP / 2的行为相同。但是不会复制“传输”攻击,因为在标准中已经考虑了它们。

对缓存的攻击以与HTTP / 1类似的方式重现,并且保护类似。

消息队列攻击不适用于HTTP / 2。其中的HTTP消息分为单独的帧,带有单独的帧头,这些帧头显式确定消息的长度和结尾。好像攻击者不会更改方法并修改HTTP标头一样,这不会影响消息帧。窃取答案将失败。即使存在以下事实,也可以

对非幂等消息的重复进行攻击最后处理的请求的通知机制在HTTP / 2中,多个请求在同一TCP中相乘,从而创建每个线程都有自己的编号。如果HTTP / 2服务器断开连接,它可以指示GOAWAY中最后处理的请求的编号。编号较高的请求始终可以安全地重定向;编号较小的请求只有在等幂时才被重定向。如果具有重写方法的请求对于代理服务器看起来是幂等的,则代理会将其转发到服务器。

如何安全地覆盖方法


简短的答案是不可能的。最好不要使用任何方法重写。并完全禁用后端支持(如果有)。阻止HTTP客户端覆盖方法。拒绝代理/ WAF,这减少了“额外”方法。

如果您必须以某种方式忍受方法的重新定义,则应防止对后端进行足够的编辑。首先,建议仅通过URI的查询组件覆盖该方法。

其次,应该有一个方法转换的白名单:可以接受的“传输”方法,以及产生的方法。当任何方法都可以覆盖任何方法时,不应有广义的转换函数。如果生成的方法没有安全性和幂等性,则“运输”方法不应具有安全性和幂等性。危险的转换应该被禁止,相同的替换GET-> HEAD。

我是否需要修补问题代理/ WAF?


如果该代理仅实现GET和POST方法,而由于一个或另一个原因阻止其他方法,则肯定是的。您可以主要针对GET和POST对其进行优化,但是阻止其他方法是一个坏主意。哪一个仍然在产品中产生不信任感:如果基本问题被阻止,那么从更复杂的问题的实施中可以期待什么呢?

如果您担心受保护的Web应用程序的安全性,那么值得从不安全的方法覆盖策略保护应用程序。当然,在一般情况下,在不了解Web应用程序实现细节的情况下,不可能完全保护应用程序免受错误覆盖,但是您可以部分覆盖根本不了解问题的用户。不仅有必要防止毒害您自己的缓存,还需要为每个受保护的应用程序启用或禁用覆盖。为此,请跟踪 常用的标头。X-HTTP方法,X-HTTP方法覆盖和X方法覆盖。跟踪URI的查询组件中的重新定义没有多大意义:高速缓存不会毒害此类请求,并且查询可能非常长并且具有完全任意的格式。

?


安全开发人员不要将应用程序开发人员限制为安全策略。他们仍然会找到解决方法,协议越灵活,它越容易实现。他们很可能不会踢您,直到您使限制变得更合理,而只是绕开它们。

如果您想出了如何在协议中实现某些内容,但是它覆盖或违背了该标准关键概念之一,那么肯定会出现兼容性和安全性问题。并且需要在决策的同时覆盖它们。每次。如果您遇到了此类建议,但没有看到安全警告,请不要在整个Internet上重复该建议。始终对决定持批评态度,找出可能出问题的地方

而不是后记


您遇到了什么代理服务器问题?必须规避什么?如何规避?

All Articles