如何正确使用HTTP_X_FORWARDED_FOR?

时间:2021-11-20 13:46:39

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_ADDR of myPROXY instead of that of the client and sends the actual IP of the client as HTTP_X_FORWARDED_FOR.

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

To overcome this, my web service has a list of 'trusted proxy' IP addresses and if REMOTE_ADDR is 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_FOR value that has multiple IP addresses. According to HTTP_X_FORWARDED_FOR documentation, 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获取具有多个IP地址的HTTP_X_FORWARDED_FOR值。根据HTTP_X_FORWARDED_FOR文档,该值是以逗号分隔的IP地址列表,其中第一个IP是实际真实客户端的IP,每个其他IP地址是代理的IP地址。

So, if HTTP_X_FORWARDED_FOR has multiple values and my service is IP restricted, do I have to check the 'last' value of HTTP_X_FORWARDED_FOR against my allowed IP list and just ignore the actual client IP?

因此,如果HTTP_X_FORWARDED_FOR有多个值并且我的服务是IP限制的,我是否必须根据我允许的IP列表检查HTTP_X_FORWARDED_FOR的“最后”值,然后忽略实际的客户端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?

6 个解决方案

#1


15  

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 '';
}

#2


14  

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在那里删除空条目。

#3


7  

In the light of the latest httpoxy vulnerabilities, there is really a need for a full example, how to use HTTP_X_FORWARDED_FOR properly.

鉴于最新的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 ();

?>

#4


1  

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

#5


0  

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

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

#6


-4  

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 this out.

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

#1


15  

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 '';
}

#2


14  

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在那里删除空条目。

#3


7  

In the light of the latest httpoxy vulnerabilities, there is really a need for a full example, how to use HTTP_X_FORWARDED_FOR properly.

鉴于最新的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 ();

?>

#4


1  

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

#5


0  

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

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

#6


-4  

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 this out.

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