在尝试弄清楚为什么我们的 Varnish 4.1 安装(在 CentOS7 上通过 varnish-cache.org repo)没有遵循 vcl 规则,该规则规定在 X-Forwarded-For 标头中记录客户端 IP 地址(请参阅:Varnish 4 记录代理/负载均衡器而不是客户端 IP 地址)我在查看 varnishlog 文件时偶然发现了一些奇怪的事情:
- Begin req 9353447 rxreq
- Timestamp Start: 1488771709.337974 0.000000 0.000000
- Timestamp Req: 1488771709.337974 0.000000 0.000000
- ReqStart 172.25.20.65 19903
- ReqMethod GET
- ReqURL /about-us/
- ReqProtocol HTTP/1.1
- ReqHeader host: www.<notreallythishost>.com
- ReqHeader Accept: */*
- ReqHeader Accept-Encoding: gzip, deflate
- ReqHeader Cache-Control: no-cache
- ReqHeader From: bingbot(at)microsoft.com
- ReqHeader Pragma: no-cache
- ReqHeader User-Agent: Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)
- ReqHeader X-Forwarded-For: 40.77.167.41
- ReqHeader X-Forwarded-Port: 80
- ReqHeader X-Forwarded-Proto: http
- ReqHeader Connection: keep-alive
- ReqUnset X-Forwarded-For: 40.77.167.41
- ReqHeader X-Forwarded-For: 40.77.167.41, 172.25.20.65
- VCL_call RECV
- ReqUnset X-Forwarded-For: 40.77.167.41, 172.25.20.65
- ReqHeader X-Forwarded-For: 172.25.20.65
- ReqUnset Accept-Encoding: gzip, deflate
- ReqHeader Accept-Encoding: gzip
- ReqUnset User-Agent: Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)
- VCL_return hash
- VCL_call HASH
- VCL_return lookup
- VCL_call MISS
- VCL_return fetch
- Link bereq 9353449 fetch
- Timestamp Fetch: 1488771709.338395 0.000421 0.000421
- RespProtocol HTTP/1.1
这充分解释了为什么无论我们使用哪种日志记录技术,我们都无法获得通过 varnishncsa 记录的负载均衡器 IP 地址以外的任何信息。
看起来,在请求处理过程中,它通过将 AWS 负载均衡器 IP 地址添加到标头来构建 X-Forwarded-For 标头,但在调用 vc_call 时,它会再次将其解构并删除原始客户端 IP 地址。那么,我该如何保持 X-Forwarded-For 的完整性,为什么 Varnish 会将 IP 从左侧移开,而不是像应该的那样将它们添加到 X-Forwarded-For 标头上?错误?
答案1
因此,解决这个问题(4.1.3-1.el7.x86_64 中可能存在的错误)的方法是,我在浏览其他 varnish 日志问题时找到的线索,特别是完全禁用 x-warded-for 标头。
虽然这不是我想要做的,但它提供了关于防止 varnish 将其自己的 vcl_recv 内容附加到我的 vcl_recv 函数定义的底部的提示。具体提供你自己的返回(查找)(尽管清漆 <= 3)或返回(哈希)(清漆4.x)。
所以现在我在 vcl_recv() 的顶部有这个:
# ensure proper logging of x-forwarded-for IP addresses
std.collect(req.http.x-forwarded-for);
set req.http.x-forwarded-for = regsub ( req.http.x-forwarded-for, "^(([0-9]{1,3}\.){3}[0-9]{1,3})(.*)", "\1" );
if (req.http.x-forwarded-for) {
std.log("ip:" + req.http.x-forwarded-for);
} else {
std.log("ip:" + client.ip);
}
然后,在函数的最后我当然提到了:
return (hash);
因此,现在它已成功记录客户端 IP 地址,并添加了 varnishncsa 选项:
-F "%%{VCL_Log:ip}x %%l %%u %%t \"%%r\" %%s %%b \"%%{Referer}i\" \"%%{User-agent}i\""
希望其他人发现这些信息有用。
更新:我发现了一个问题关于欺骗的帖子请见此 nginx 答案如果有某种真实 IP 地址或受信任的 IP 地址varnish 中的 headers 也是如此,但目前似乎不是原生的。在这种情况下,我的初始解决方案将挑选出欺骗地址。因此,最好使用删除已知 IP 的正则表达式,然后选择第一个未处理的客户端 IP。类似这样的方法可以工作:
set req.http.x-forwarded-for = regsub ( req.http.x-forwarded-for, "(([0-9]{1,3}\.){3}[0-9]{1,3})(, (172.25.20.65|172.25.10.228),?)+$", "\1" );
其中 172.25.20.65 和 172.25.10.228 是我的受信任 IP(代理或负载均衡器拾取并添加到 X-Forwarded-For 等)。根据您是否希望在其前面看到代理/LB,您的正则表达式可以是这样的(如果您希望标头中始终至少有一个负载均衡器/代理):
(([0-9]{1,3}\.){3}[0-9]{1,3})(, (<trustedip1>|<trustedip2>|...),?)+$
或者如果允许在 varnish 服务器之前没有任何内容,则这样做:
(([0-9]{1,3}\.){3}[0-9]{1,3})(, (<trustedip1>|<trustedip2>|...),?)*$
尽管如果是后者,那么您为什么要查看 x-forwarded-for 标头......