我的请求流程如下;
HAProxy --> Varnish (4.0.1) --> Apache web backends
当新请求进入HAProxy时,客户端的IP地址将被添加到X-Forwarded-For
标头中(这很好!).但是,看起来Varnish HAProxy
也在添加IP.当请求到达我的vcl_recv
例程时,X-Forwarded-For
标题是:
X-Forwarded-For: end-user-ip, haproxy-ip
你可以在varnishlog
输出中看到:
* << Request >> 8 - Begin req 7 rxreq - Timestamp Start: 1409262358.542659 0.000000 0.000000 - Timestamp Req: 1409262358.542659 0.000000 0.000000 - ReqStart 192.168.1.103 48193 - ReqMethod PURGE - ReqURL /some/path - ReqProtocol HTTP/1.1 - ReqHeader Authorization: Basic xxx - ReqHeader User-Agent: curl/7.30.0 - ReqHeader Host: example.com - ReqHeader Accept: */* - ReqHeader X-Forwarded-For: 1.2.3.4 - ReqHeader Connection: close - ReqUnset X-Forwarded-For: 1.2.3.4 - ReqHeader X-Forwarded-For: 1.2.3.4, 192.168.1.101 - VCL_call RECV - ReqUnset X-Forwarded-For: 1.2.3.4, 192.168.1.101 - VCL_acl NO_MATCH purge_acl - Debug "VCL_error(403, Not allowed.)" - VCL_return synth
我需要准确的客户端IP地址的原因是我可以根据PURGE
/的ACL规则检查它BAN
.由于X-Forwarded-For
标头中的最后一个IP 是HAProxy的IP,因此所有IP的ACL检查都会失败.这是我的配置的相关部分:
acl purge_acl { "1.2.3.4"; } sub vcl_recv { set req.backend_hint = load_balancer.backend(); if (req.method == "PURGE") { if (!std.ip(req.http.X-forwarded-for, "0.0.0.0") ~ purge_acl) { return(synth(403, "Not allowed.")); } ban("obj.http.x-url ~ " + req.url); return(synth(200, "Ban added")); } }
任何想法如何我可以完全依赖X-Forwarded-For
HAProxy 的标题,没有Varnish篡改它?
旁注,似乎Varnish正在这样做(尽管这不是在mv VCL配置中):
if (req.restarts == 0) { if (req.http.X-Forwarded-For) { set req.http.X-Forwarded-For = req.http.X-Forwarded-For + ", " + client.ip; } else { set req.http.X-Forwarded-For = client.ip; } }
laz.. 9
Varnish将其默认逻辑附加到您定义的任何函数,vcl_recv
而不是纯粹覆盖它.默认vcl_recv
逻辑包含:
if (req.http.x-forwarded-for) { set req.http.X-Forwarded-For = req.http.X-Forwarded-For + ", " + client.ip; } else { set req.http.X-Forwarded-For = client.ip; }
你注意到了 对我来说似乎很奇怪的是,看起来Varnish的默认逻辑在vcl_recv
你的vcl_recv
逻辑之前执行.你看到的是什么值X-Forwarded-For
之内vcl_deliver
,如果你定义自己?
您可以做的一件事是在必要时解析出这样的第一个IP地址:
set req.http.X-Forwarded-For = regsub(req.http.X-Forwarded-For, "^([^,]+),?.*$", "\1");
Razvan Grigo.. 9
我今天也遇到了这个问题.
该default.vcl
清漆4.0在改名builtin.vcl
,并且不包含set req.http.X-Forwarded-For
你所提到的部分- 链接.然而,他明确地按照协议规范 - 维基百科链接将逗号分隔的列表附加到中间代理IP地址.
一种解决方案是使用X-Real-IP
头文件,在HAProxy中使用真实客户端ip一直覆盖此头文件,并将此文件用于vcl ACL.
在清漆论坛中提到的另一个解决方案(错误地)将regsub(req.http.X-Forwarded-For, "[, ].*$", "")
采用最左边的IP地址.但是,这种方法并不安全,因为这个标题很容易被欺骗.
我的建议是从标题中提取已知部分,清漆IP,如下所示:
if (!std.ip(regsub(req.http.X-Forwarded-For, ", 192\.168\.1\.101$", ""), "0.0.0.0") ~ purge_acl) { return(synth(403, "Not allowed.")); }
唯一的问题是如果连接中有超过2个跃点,例如.您还使用代理连接到互联网.nginx
由于您可以定义受信任的跃点,因此可以提供一个很好的解决方案,并且它们会被递归忽略,直到真正的客户端ip.
set_real_ip_from 192.168.1.101; real_ip_header X-Forwarded-For; real_ip_recursive on;
您可以在此serverfault线程答案中查看有关此内容的更多详细信息
您可能还想检查您在ACL匹配之前VCL_call RECV
执行的原因ReqUnset X-Forwarded-For
.