反向代理的攻击面 (下)
Posted nginx遇上redis
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了反向代理的攻击面 (下)相关的知识,希望对你有一定的参考价值。
让我们接着上节的内容,继续探讨。建议读者先阅读第一部分,这将有助于理解本节的内容。
服务端攻击
请求错误路由
例子2
这是关于nginx的一个“bug”,准确的说它只是Nignx正常工作导致的(因此不会被修复)。
首先,服务器配置的规则为location /to_app
,即/to_app
是作为后面添加字符的前缀。因此,/to_app
,/to_app/
,/to_app_anything
(包括特殊符号)都可以通过该规则。并且,/to_app
后面的字符将被提取并与proxy_pass
联合(解析)起来。
Nginx处理完/to_app_anything
后,其转发(到后端服务器)的请求格式为http://server/any_path/_anything
。
location /to_app {
proxy_pass http://server/any_path/;
}
如果将这些特性结合起来,可以发现我们可以遍历后端服务器的所有位置。只需发送这样的请求:
GET /to_app../other_path HTTP/1.1
解释:首先/to_app
与Nginx规则相匹配,然后Nginx提取出../other_path
,再与proxy_pass
的/any_path/
相结合,最终转发的请求为:http://server/any_path/../other_path
。当后端服务器解析完毕后,我们就能够进入想要的目录。
例子3
在上篇文章开头,我已经介绍了反向代理服务器会根据主机头来转发请求至后端。
这里我使用Haproxy来举个例子。我将Haproxy配置为所有主机头为example1
的请求都将转发至名为example1_backend
– 192.168.78.1:9999
的后端服务器。
frontend http-in
acl host_example1 hdr(host) -i example1.com
use_backend example1_backend if host_example1
backend example1_backend
server server1 192.168.78.1:9999 maxconn 32
对于这样的配置,攻击者似乎无法再访问后端的其他服务器?其实不然,攻击者可以轻易突破防线。因为Haproxy 不支持Absolute URI
(上篇文章中介绍过了),然而大部分web服务器都支持此协议。当Haproxy 收到包含Absolute URI
的请求时,它不会对Absolute URI
做任何处理,直接转发至后端。因此,我们可以发送以下请求来访问其他后端服务器。
GET http://unsafe-value/path/ HTTP/1.1
Host: example1.com
那么,我们可以通过反向代理来访问其后端的任意服务器?其实在大多数情况下(Nginx, Haproxy, Varnish),这并不能轻松实现,但是Apache(某些版本)则可以。Apache从ProxyPass
“解析”提取主机值,因此我们可以发送类似GET @evil.com HTTP/1.1
的请求,Apache将其视为http://backend_server@evil.com
,然后请求evil.com
(你知道的,这可以导致SSRF攻击)。这里有一个此类攻击的例子。
客户端攻击
其实你再回过头细想方向代理的特性,你会发现只要与响应相关,就会有潜在的客户端攻击向量。由于浏览器在发送请求前通常会做一些处理,因此这类攻击有一些额外的限制,这将导致服务器会有非预期的表现。
浏览器处理
在一次客户端攻击中,攻击者需要强制受害者浏览器发送一个特殊的请求,然后服务器做出响应。但是,浏览器会遵循一些规范来处理路径,然后再发送请求。浏览器会解析该URL(例如抛弃fragment部分),对某些必要的符号进行URL编码处理(或许不会),然后在使路径变得规范化。因此,我们要想实施这种攻击,我们只能发送一个“有效”的请求。该请求必须切合这三个组件(浏览器,反向代理,后端服务器)。
当然,不同浏览器的实现(请求)存在差异,再加上一些特性上的区别,可以使我们找到一个切合点:
例如,Chrome和IE不会解码
%2f
,因此它们将不对/path/anything/..%2f../
这样的路径做规范化处理。在规范化处理之前,老版本的Firefox不做URL解码,但现在它和Chrome有类似的工作方式。
Safari不对路径做URL解码处理,因此我们可以强制(浏览器)原封不动地发送
/path/%2e%2e/another_path/
。
滥用标头修改功能
对于反向代理服务器来说,增添,删除和修改后端请求中的标头是一项基本功能。有些情况在,这比修改后端本身简单的多。有时,反向代理会添加一些重要的安全标头。作为攻击者的我们,想要利用这些规则来使反向代理服务器做出错误的响应(通过滥用后端位置标头),从而攻击其他用户。
假如我们使用Nginx作为代理,Tomcat作为后端。Tomcat默认设置了X-Frame-Options: deny
标头,所以浏览器无法将其嵌入frame中。由于某些原因,Tomcat web应用的一个组件(/iframe_safe/
)必须通过iframe访问,因此Nginx配置中删除了X-Frame-Options
标头。然而,为了服务器为了防范clickjacking
(点击劫持)攻击,做了iframe_safe
设置:
location /iframe_safe/ {
proxy_pass http://tomcat_server/iframe_safe/;
proxy_hide_header "X-Frame-Options";
}
location / {
proxy_pass http://tomcat_server/;
}
其实,作为攻击者的我们可以构造符合Nginx的iframe_safe
规则,又能被后端Tomcat解析为完全不同的(访问)位置:
<iframe src="http://nginx_with_tomcat/iframe_safe/..;/any_other_path">
浏览器不会对其做规范化处理。这又符合Nignx的iframe_safe
规则。Tomcat支持路径中插入参数,取/any_other_path
。所以在这样的配置下,通过frame可以访问Tomcat的所有位置,这将导致clickjacking
(点击劫持)攻击。
做一些思维发散,我们可以利用它来滥用其他安全有关的标头(例如:CORS, CSP)。
缓存
缓存是最有趣的攻击向量之一,对于各类攻击都有很好的开发潜力。但是在反向代理领域利用缓存(攻击的方法)仍然鲜为人知。最近,与缓存相关的攻击越来越受关注了,网上有一些很酷的研究例如Web缓存欺骗和实用的Web缓存中毒。在本篇文章中我也关注到了缓存:我想要分析出缓存的各种实现,从而有助于研究出缓存欺骗和缓存中毒攻击的方法。
它是如何工作的
我将介绍一些反向代理中关于缓存的要点,这将帮助你理解这类攻击。
实现缓存的方式很简单。在某些情况下,一台反向代理服务器会将来自后端的响应存储到缓存中,以后直接调用缓存而不用访问后端服务器。一些反向代理服务器默认支持缓存,另一些则要求用户自行配置。一般来说,反向代理服务器会使用缓存标志,该标志与请求的主机头值和路径相关联。
反向代理对某个响应缓存与否,它会先检查请求中的Cache-Control
和Set-Cookie
标头。反向代理不会对存在Set-Cookie
标头的请求做任何缓存,但是对于Cache-Control
有些不同。它会将其视为缓存策略,请求额外的解析。Cache-control
标头框架非常复杂,但是有基本的功能标志,例如决定是否缓存,设置缓存时限等。
Cache-control
标头形式有下面这些:
Cache-Control: no-cache, no-store, must-revalidate
Cache-Control: public, max-age=31536000
第一个是禁止反向代理缓存,第二个相反。Cache-control
标头滥用是允许反向代理储存响应。
大量的web服务器,应用服务器和框架自动且正确地设置Cache-control
标头。在大部分情况下,如果web应用的某个脚本使用了session
功能,那么该应用会严格设置Cache-control
标头的缓存功能,因此如遇到这种情况,开发者不需要考虑(安全)。然而有例外,例如,如果web应用使用它自己的session
安全机制,Cache-control
标头可能会存在漏洞。
攻击
反向代理的一个常用功能是“积极缓存”(这不是官方词汇,但可以描述其作用)。在一种情况下(后端严格限制,完全不允许缓存),管理员没有修改后端,而是修改反向代理规则,修改严格的Cache-control
标头从而开启了缓存响应。这时,管理员一般都会错误设置。例如,只缓存响应中某些扩展名(.jpg
, .css
, .js
)或者某个路径(/images/
)。
如果是这种情况,攻击者可以创建符合反向代理规则又被后端误判的路径。
这里还是Nginx+Tomcat的组合。下面这条规则强制使Nginx缓存Tomcat上/images
目录的所有响应。
location /images {
proxy_cache my_cache;
proxy_pass http://tomcat_server;
proxy_cache_valid 200 302 60m;
proxy_ignore_headers Cache-Control Expires;
}
作为攻击者,我们可以滥用该规则,从而实现web缓存欺骗。只需受害者打开下面的这个URL(例如使用img
)。
<img src="http://nginx_with_tomcat.com/images/..;/index.jsp">
然后受害者的浏览器将发送请求(携带经认证的cookie)。Nginx发现请求中存在/image
,于是直接转发该请求值Tomcat,然后缓存响应(Tomcat->Nginx,此时Cache-Control
标头无效)。Tomcat在处理时将甄别出/index.jsp
,因此攻击者可以强制Nginx缓存任何页面,攻击者仅需更改路径/images/..;/index.jsp
从而盗取受害者的敏感数据(例如token->csrf攻击)。
这看起来只是一个web缓存欺骗的变种,但其实不然。
让我们来考虑缓存中毒攻击。此类攻击依赖于在请求中找到未加密的值(标头),这将显著地影响(从安全角度)接下来的响应,但是在这里,这个响应必须由反向代理服务器缓存,同时Cache-Control
标头应当设置为允许。如果我们把所有东西中和起来,我们能够找出一些方法来造成缓存中毒攻击。
让我们想象一下这个场景。有一台Nuster(基于Haproxy的缓存代理)服务器和一个web应用。这个web应用上的/account/attacker
有一处self-XSS漏洞(只在攻击者自己的账户上触发)。Nuster配置了缓存web应用上/img/
目录的所有响应。
nuster cache on
nuster rule img ttl 1d if { path_beg /img/ }
攻击者仅需构造特殊URL/img/..%2faccount/attacker/
,Nuster将会应用“积极缓存”规则,这时web应用返回self-XSS响应(可以看到存在/account/attacker/
)。这个带有XSS Payload的响应将被Nuster缓存,因此攻击者结合XSS与缓存滥用来攻击该应用的用户。这就是从self-XSS到正常XSS的一种方法。
看完本文有收获?请转发分享更多人
以上是关于反向代理的攻击面 (下)的主要内容,如果未能解决你的问题,请参考以下文章