php 如何正确使用 HTTP_X_FORWARDED_FOR?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11452938/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to use HTTP_X_FORWARDED_FOR properly?
提问by kingmaple
Alright, I have an small authentication issue. My web service allows to connect to my API over HTTP with a username and password, but this connection can also be restricted to a specific IP address.
好的,我有一个小的身份验证问题。我的 Web 服务允许使用用户名和密码通过 HTTP 连接到我的 API,但此连接也可以限制为特定的 IP 地址。
This means that the $_SERVER['REMOTE_ADDR']can be incorrect. I already know that any IP information can never truly be relied upon - I have the restriction only in an attempt to add another layer of security.
这意味着$_SERVER['REMOTE_ADDR']可能是不正确的。我已经知道任何 IP 信息都无法真正依赖——我有这个限制只是为了增加另一层安全性。
If this is the general overview of a request to my web server:
如果这是对我的 Web 服务器的请求的一般概述:
clientSERVER => clientPROXY => myPROXY => mySERVER
clientSERVER => clientPROXY => myPROXY => mySERVER
Then this means that mySERVER shows REMOTE_ADDRof myPROXY instead of that of the client and sends the actual IP of the client as HTTP_X_FORWARDED_FOR.
那么这意味着 mySERVER 显示的REMOTE_ADDR是 myPROXY 而不是客户端的,并将客户端的实际 IP 作为HTTP_X_FORWARDED_FOR.
To overcome this, my web service has a list of 'trusted proxy' IP addresses and if REMOTE_ADDRis from one of those trusted IP addresses, then it tells my web service that the actual IP address is the value of HTTP_X_FORWARDED_FOR.
为了克服这个问题,我的 Web 服务有一个“受信任的代理”IP 地址列表,如果REMOTE_ADDR来自这些受信任的 IP 地址之一,那么它会告诉我的 Web 服务实际 IP 地址是 的值HTTP_X_FORWARDED_FOR。
Now the problem is with clientPROXY. This means that (quite often) mySERVER gets HTTP_X_FORWARDED_FORvalue that has multiple IP addresses. According to HTTP_X_FORWARDED_FORdocumentation, the value is a comma-separated list of IP addresses where the first IP is that of the actual true client and every other IP address is that of a proxy.
现在的问题是clientPROXY。这意味着(经常)mySERVER 获得HTTP_X_FORWARDED_FOR具有多个 IP 地址的值。根据HTTP_X_FORWARDED_FOR文档,该值是一个以逗号分隔的 IP 地址列表,其中第一个 IP 是实际真实客户端的 IP 地址,其他所有 IP 地址都是代理的 IP 地址。
So, if HTTP_X_FORWARDED_FORhas multiple values and my service is IP restricted, do I have to check the 'last' value of HTTP_X_FORWARDED_FORagainst my allowed IP list and just ignore the actual client IP?
因此,如果HTTP_X_FORWARDED_FOR有多个值并且我的服务受 IP 限制,我是否必须根据HTTP_X_FORWARDED_FOR允许的 IP 列表检查“最后一个”值而忽略实际的客户端 IP?
I assume that in a system, where I have to set the list of allowed IP addresses, the whitelisted IP address should be that of a proxy and not an IP that is behind the proxy (since that could be some localhost IP and change frequently).
我假设在一个系统中,我必须设置允许的 IP 地址列表,列入白名单的 IP 地址应该是代理的 IP 地址而不是代理后面的 IP(因为它可能是一些本地主机 IP 并且经常更改) .
And what of HTTP_CLIENT_IP?
还有什么HTTP_CLIENT_IP?
回答by Hrishikesh Mishra
You can use this function to get proper client IP:
您可以使用此功能获取正确的客户端 IP:
public function getClientIP(){
if (array_key_exists('HTTP_X_FORWARDED_FOR', $_SERVER)){
return $_SERVER["HTTP_X_FORWARDED_FOR"];
}else if (array_key_exists('REMOTE_ADDR', $_SERVER)) {
return $_SERVER["REMOTE_ADDR"];
}else if (array_key_exists('HTTP_CLIENT_IP', $_SERVER)) {
return $_SERVER["HTTP_CLIENT_IP"];
}
return '';
}
回答by user336828
I like Hrishikesh's answer, to which I only have this to add...because we saw a comma-delimited string coming across when multiple proxies along the way were used, we found it necessary to add an explode and grab the final value, like this:
我喜欢 Hrishikesh 的答案,我只需要添加这个……因为我们看到在使用多个代理时出现了一个逗号分隔的字符串,我们发现有必要添加一个爆炸并获取最终值,例如这个:
$IParray=array_values(array_filter(explode(',',$_SERVER['HTTP_X_FORWARDED_FOR'])));
return end($IParray);
the array_filter is in there to remove empty entries.
array_filter 在那里删除空条目。
回答by Erki Aring
In the light of the latest httpoxyvulnerabilities, there is really a need for a full example, how to use HTTP_X_FORWARDED_FORproperly.
针对最新的httpoxy漏洞,确实需要一个完整的例子,如何HTTP_X_FORWARDED_FOR正确使用。
So here is an example written in PHP, how to detect a client IP address, if you know that client may be behind a proxy and you know this proxy can be trusted. If you don't known any trusted proxies, just use REMOTE_ADDR
所以这里有一个用 PHP 编写的例子,如果你知道客户端可能在代理后面并且你知道这个代理是可信的,那么如何检测客户端 IP 地址。如果您不知道任何受信任的代理,请使用REMOTE_ADDR
<?php
function get_client_ip ()
{
// Nothing to do without any reliable information
if (!isset ($_SERVER['REMOTE_ADDR'])) {
return NULL;
}
// Header that is used by the trusted proxy to refer to
// the original IP
$proxy_header = "HTTP_X_FORWARDED_FOR";
// List of all the proxies that are known to handle 'proxy_header'
// in known, safe manner
$trusted_proxies = array ("2001:db8::1", "192.168.50.1");
if (in_array ($_SERVER['REMOTE_ADDR'], $trusted_proxies)) {
// Get the IP address of the client behind trusted proxy
if (array_key_exists ($proxy_header, $_SERVER)) {
// Header can contain multiple IP-s of proxies that are passed through.
// Only the IP added by the last proxy (last IP in the list) can be trusted.
$proxy_list = explode (",", $_SERVER[$proxy_header]);
$client_ip = trim (end ($proxy_list));
// Validate just in case
if (filter_var ($client_ip, FILTER_VALIDATE_IP)) {
return $client_ip;
} else {
// Validation failed - beat the guy who configured the proxy or
// the guy who created the trusted proxy list?
// TODO: some error handling to notify about the need of punishment
}
}
}
// In all other cases, REMOTE_ADDR is the ONLY IP we can trust.
return $_SERVER['REMOTE_ADDR'];
}
print get_client_ip ();
?>
回答by zeroimpl
You can also solve this problem via Apache configuration using mod_remoteip, by adding the following to a conf.d file:
您还可以使用mod_remoteip通过 Apache 配置解决此问题,方法是将以下内容添加到 conf.d 文件中:
RemoteIPHeader X-Forwarded-For
RemoteIPInternalProxy 172.16.0.0/12
LogFormat "%a %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
回答by mowgli
If you use it in a database, this is a good way:
如果你在数据库中使用它,这是一个好方法:
Set the ip field in database to varchar(250), and then use this:
将数据库中的 ip 字段设置为 varchar(250),然后使用:
$theip = $_SERVER["REMOTE_ADDR"];
if (!empty($_SERVER["HTTP_X_FORWARDED_FOR"])) {
$theip .= '('.$_SERVER["HTTP_X_FORWARDED_FOR"].')';
}
if (!empty($_SERVER["HTTP_CLIENT_IP"])) {
$theip .= '('.$_SERVER["HTTP_CLIENT_IP"].')';
}
$realip = substr($theip, 0, 250);
Then you just check $realip against the database ip field
然后你只需对照数据库 ip 字段检查 $realip
回答by TheEnvironmentalist
HTTP_CLIENT_IP is the most reliable way of getting the user's IP address. Next is HTTP_X_FORWARDED_FOR, followed by REMOTE_ADDR. Check all three, in that order, assuming that the first one that is set (isset($_SERVER['HTTP_CLIENT_IP'])returns true if that variable is set) is correct. You can independently check if the user is using a proxy using various methods. Check thisout.
HTTP_CLIENT_IP 是获取用户 IP 地址的最可靠方式。接下来是 HTTP_X_FORWARDED_FOR,然后是 REMOTE_ADDR。按顺序检查所有三个,假设设置的第一个(isset($_SERVER['HTTP_CLIENT_IP'])如果设置了该变量,则返回 true)是正确的。您可以使用各种方法独立检查用户是否正在使用代理。看看这个。

