如何正确使用HTTP_X_FORWARDED_FOR?

问题描述 投票:30回答:6

好吧,我有一个小的身份验证问题。我的Web服务允许使用用户名和密码通过HTTP连接到我的API,但此连接也可以限制为特定的IP地址。

这意味着$_SERVER['REMOTE_ADDR']可能不正确。我已经知道任何IP信息都无法真正依赖 - 我只有在尝试添加另一层安全性时才有限制。

如果这是对我的Web服务器的请求的一般概述:

clientSERVER => clientPROXY => myPROXY => mySERVER

那么这意味着mySERVER显示myPROXY的REMOTE_ADDR而不是客户端的HTTP_X_FORWARDED_FOR,并将客户端的实际IP发送为REMOTE_ADDR

为了解决这个问题,我的Web服务有一个“可信代理”IP地址列表,如果HTTP_X_FORWARDED_FOR来自其中一个可信IP地址,那么它告诉我的Web服务实际IP地址是HTTP_X_FORWARDED_FOR的值。

现在问题出在clientPROXY上。这意味着(通常)mySERVER获取具有多个IP地址的HTTP_X_FORWARDED_FOR值。根据HTTP_X_FORWARDED_FOR文档,该值是以逗号分隔的IP地址列表,其中第一个IP是实际真实客户端的IP,每个其他IP地址是代理的IP地址。

所以,如果HTTP_X_FORWARDED_FOR有多个值且我的服务是IP限制的,我是否必须检查HTTP_CLIENT_IP的“最后”值与我允许的IP列表并忽略实际的客户端IP?

我假设在一个系统中,我必须设置允许的IP地址列表,白名单IP地址应该是代理的IP地址而不是代理后面的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 ''; }

php proxy ip forwarding
6个回答
20
投票

您可以使用此功能获取正确的客户端IP:

$IParray=array_values(array_filter(explode(',',$_SERVER['HTTP_X_FORWARDED_FOR'])));
return end($IParray);

17
投票

我喜欢Hrishikesh的答案,我只想添加它...因为我们看到在使用多个代理时遇到逗号分隔的字符串,我们发现有必要添加一个爆炸并获取最终值,如这个:

httpoxy

array_filter在那里删除空条目。


12
投票

鉴于最新的HTTP_X_FORWARDED_FOR漏洞,确实需要一个完整的例子,如何正确使用REMOTE_ADDR

所以这里有一个用PHP编写的例子,如何检测客户端IP地址,如果你知道客户端可能在代理后面,你知道这个代理可以信任。如果您不知道任何受信任的代理,请使用<?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 (); ?>

mod_remoteip

1
投票

您还可以使用RemoteIPHeader X-Forwarded-For RemoteIPInternalProxy 172.16.0.0/12 LogFormat "%a %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined 通过Apache配置解决此问题,方法是将以下内容添加到conf.d文件中:

$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);

0
投票

如果您在数据库中使用它,这是一个好方法:

将数据库中的ip字段设置为varchar(250),然后使用:

isset($_SERVER['HTTP_CLIENT_IP'])

然后你只需检查$ realip对数据库ip字段


-4
投票

HTTP_CLIENT_IP是获取用户IP地址的最可靠方式。接下来是HTTP_X_FORWARDED_FOR,然后是REMOTE_ADDR。假设所设置的第一个(如果设置了该变量,this返回true)是正确的,则按顺序检查所有三个。您可以使用各种方法独立检查用户是否正在使用代理。检查qazxswpoi了。

© www.soinside.com 2019 - 2024. All rights reserved.