好吧,我有一个小的鉴定问题。 我的网络服务允许在同一个用户名和密码的HTTP连接到我的API,但是这种连接也被限制到特定的IP地址。
这意味着, $_SERVER['REMOTE_ADDR']
可能不正确。 我已经知道任何IP信息可从来没有真正地依靠 - 我也有限制,只在尝试添加另一层安全。
如果这是我的Web服务器的请求的概述:
clientSERVER => clientPROXY => myPROXY => mySERVER
那么这意味着MYSERVER显示REMOTE_ADDR
MYPROXY,而不是客户端的发送客户端的实际IP HTTP_X_FORWARDED_FOR
。
为了克服这个问题,我的web服务具有“信任代理的IP地址的列表,如果REMOTE_ADDR
是从那些值得信赖的IP地址中的一个,那么它告诉我的web服务的实际IP地址的值HTTP_X_FORWARDED_FOR
。
现在的问题是clientPROXY。 这意味着,(经常)MYSERVER得到HTTP_X_FORWARDED_FOR
具有多个IP地址的值。 据HTTP_X_FORWARDED_FOR
文件,该值是一个逗号分隔的IP地址列表,其中第一个IP是,实际真正的客户和所有其他IP地址是代理的。
所以,如果HTTP_X_FORWARDED_FOR
有多个值,我的服务是IP限制,我必须要检查的“最后”值HTTP_X_FORWARDED_FOR
对我的允许的IP列表,只是忽略了实际的客户端IP?
我认为在一个系统,在这里我必须设置允许的IP地址列表,白名单上的IP地址应该是一个代理,而不是一个IP是代理的背后(因为这可能是一些本地主机的IP,并经常变化) 。
和什么HTTP_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 '';
}
我喜欢Hrishikesh的答案,而我只是有这个加...因为我们看到了一个逗号分隔字符串时使用沿途多个代理跨越未来,我们认为有必要增加一个爆炸并抓住最后的值,如这个:
$IParray=array_values(array_filter(explode(',',$_SERVER['HTTP_X_FORWARDED_FOR'])));
return end($IParray);
该array_filter是在里面删除空项。
在最新的光httpoxy漏洞,实在需要一个完整的例子,如何使用HTTP_X_FORWARDED_FOR
正常。
因此,这里是用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 ();
?>
您也可以使用通过解决Apache配置这个问题mod_remoteip ,加入以下到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
如果您在数据库中使用它,这是一个好办法:
设置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);
然后你只需核对数据库IP字段$ realip
HTTP_CLIENT_IP是获取用户的IP地址的最可靠的方法。 接下来是HTTP_X_FORWARDED_FOR,其次是REMOTE_ADDR。 检查所有三个,按照这个顺序,假设所设定的第一个( isset($_SERVER['HTTP_CLIENT_IP'])
如果变量设置返回true)是正确的。 您可以单独检查,如果用户使用的是不同的方法使用代理。 检查这个出来。