在 apache 中将 REMOTE_ADDR 设置为 X-Forwarded-For

Posted

技术标签:

【中文标题】在 apache 中将 REMOTE_ADDR 设置为 X-Forwarded-For【英文标题】:Set REMOTE_ADDR to X-Forwarded-For in apache 【发布时间】:2011-01-15 21:11:43 【问题描述】:

在 Apache 位于反向代理(例如 Squid)之后的情况下,cgi 环境变量 REMOTE_ADDR 获取代理的地址而不是客户端的地址。

但是,代理会设置一个名为 X-Forwarded-For 的标头来包含客户端的原始 IP 地址,以便 Apache 可以看到它。

问题是,我们如何让 Apache 将 REMOTE_ADDR 替换为 X-Forwarded-For 标头中的值,以便所有 Web 应用程序都能透明地看到正确的地址?

【问题讨论】:

【参考方案1】:

您可以为此使用 mod_rpaf。 http://stderr.net/apache/rpaf/

【讨论】:

我正在为此 +1,但要注意显然 rpaf 不占用网络范围。因此,如果您的提供商正在为您进行平衡,您必须希望他们永远不会更改其平衡器 IP。此外,ubuntu 12.04 无法正确加载 conf,您必须在 rpaf.conf 中注释掉 和关闭的 ,否则它不会加载该 conf。 @DevNull:查看更新的 mod_rpaf,它支持 CDIR 范围。 github.com/gnif/mod_rpaf。这个存储库现在是官方的,因为我得到了原作者的许可。 @Geoffrey,很高兴你接手了。我在托管公司使用的平衡器说来源将通过 /24 网络,对于较旧的 rpaf,我必须输入 253 个条目,每个可能的 IP 一个。 Apache 2.4 有一个内置的 mod_remoteip 可以做到这一点,从而使 mod_rpaf 过时了。【参考方案2】:

请记住,此值可能会被欺骗。请参阅 http://blog.c22.cc/2011/04/22/surveymonkey-ip-spoofing/ 了解具有跨站点脚本后果的真实示例。

【讨论】:

这就是为什么我看到的每个执行此翻译的机制(包括 maciekb 提到的非常有用的 rpaf 模块)都使用 REMOTE_HOST 白名单,以便您知道您来自受信任的代理。 【参考方案3】:

请注意,如果请求已遍历多个代理,则 X-Forwarded-For 标头可能包含 IP 地址的列表。在这种情况下,您通常需要最左边的 IP。您可以使用 SetEnvIf 提取它:

SetEnvIf X-Forwarded-For "^(\d1,3+\.\d1,3+\.\d1,3+\.\d1,3+).*" XFFCLIENTIP=$1

注意使用 $1 来设置 XFFCLIENTIP 环境变量以保存正则表达式中第一组的内容(在括号中)。

然后您可以使用环境变量的值来设置标头(或在 Apache 日志格式中使用它,以便日志包含实际的客户端 IP)。

【讨论】:

我认为您的正则表达式不正确:您想获取X-Forwarded-For 标头中最右侧的IP 地址,而不是最左侧的IP 地址。你的表达应该是"^.*?(\d1,3+\.\d1,3+\.\d1,3+\.\d1,3+$" 我知道***是权威来源,但它目前指出最左边的 IP 是客户端:en.wikipedia.org/wiki/X-Forwarded-For 那么,我应该相信谁? :) 所以最左边的确实是客户端的IP,但是,之后的每个IP地址都应该被检查和验证为所谓的可信代理。作为先决条件,您必须验证这些代理中的每一个是否还检查他们的请求是否有意义。他们应该检查的是客户端欺骗,从而发送X-Forwarded-By 标头。【参考方案4】:

除了前面提到的mod_rpaf,mod_extract_forwarded 似乎也将执行此功能。

mod_extract_forwarded 的一个优点是它可以从EPEL 用于 RHEL/CentOS 服务器,而mod_rpaf 不可用。

这两个模块似乎都不允许您将整个代理服务器子网列入白名单,这就是 CloudFlare 人员创建自己的插件的原因:mod_cloudflare,应该注意的是,不是 em> 像其他两个一样的通用工具;它包含一个硬编码的 CloudFlare 子网列表。

【讨论】:

【参考方案5】:

是的,我们可以做到。

只需在您的 php.ini 中添加一个 auto_prepend_file,例如 auto_prepend_file = "c:/prepend.php" 并在此文件中添加:

if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) 
    $_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_X_FORWARDED_FOR'];

您需要 Apache 宽度 RemoteIPHeader X-Real-IP 的 MOD_REMOTEIP。

干杯,

吉雷马赫

【讨论】:

我看不到 OP 提到了关于 PHP 的任何内容。如果你不知道的话,除了 PHP 还有其他的服务器端技术。 你缺少explode(',')、end()和trim()【参考方案6】:

很遗憾,

在撰写本文时,freshports.org、people.apache.org 或 gist.github.com 的反向移植和分支都没有工作。它们都基于 apache httpd 2.3 的早期 alpha 版本,既不兼容当前版本的 2.2 也不兼容 2.4。

因此,在浪费时间尝试调整后向端口以创建真正的 httpd 2.2 工作后,我决定迁移到 httpd 2.4。在 httpd 2.4 中,mod_remoteip 工作顺利,即使负载均衡器具有永久保持连接,它用于将来自不同实际客户端 IP 地址的请求代理到后端。我不确定其他模块是否可以处理这种情况(在同一连接中更改每个请求的客户端 IP 地址)。

【讨论】:

【参考方案7】:

您可以安装模块 mod_extract_forwarded 并将 MEFaccept 参数设置为 all。

【讨论】:

【参考方案8】:

目前推荐使用 apache 模块 mod_remoteip 来执行此操作; rpaf 没有得到可靠的维护,可能会导致问题。

【讨论】:

【参考方案9】:

Apache 2.4 开始,有 mod_remoteip 内置模块可以做到这一点。

    启用mod_remoteip (例如a2enmod remoteip

    创建受信任 IP 范围的列表(您接受远程 IP 标头的 IP)。你可以把它们放在像conf/trusted-ranges.txt这样的文件中

    将此行添加到 Apache 配置中:

    RemoteIPTrustedProxyList conf/trusted-ranges.txt
    

    更改您的日志文件格式以使用 %a 而不是 %h 来记录客户端 IP。


对于 Cloudflare,您需要信任他们的所有 IP 范围使用自定义标头 CF-Connecting-IP

RemoteIPHeader CF-Connecting-IP

您可以像这样获得 Cloudflare 范围:

curl https://www.cloudflare.com/ips-v4 > trusted-ranges.txt
curl https://www.cloudflare.com/ips-v6 >> trusted-ranges.txt

【讨论】:

以上是关于在 apache 中将 REMOTE_ADDR 设置为 X-Forwarded-For的主要内容,如果未能解决你的问题,请参考以下文章

如何在 crate 中将 Rust 项目设为公开,但在其外部设为私有?

在派生类中将属性设为只读

如何在 Ruby 中将实例变量设为私有?

在 Python 中将类实例属性设为只读

在 Wordpress 中将图像设为私有

如何在 Sencha EXT JS 中将我的标签设为超链接