Martin AJ Martin AJ - 5 months ago 13
PHP Question

Why should I store both REMOTE and FORWARDED as user's IP?

Currently I get usr's IP like this:

if ( isset($_SERVER['HTTP_X_FORWARDED_FOR']) ){
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
} elseif ( isset($_SERVER['REMOTE_ADDR']) ) {
$ip = $_SERVER['REMOTE_ADDR'];
}

// IPs
+----+----------------+-------------+
| id | user_ip | date_time |
+----+----------------+-------------+
| 1 | 43.12.9.9 | 1468070172 |
| 2 | 173.3.0.1 | 1468070667 |
+----+----------------+-------------+





But now, I read this in here:


if you are going to save the
$_SERVER['HTTP_X_FORWARDED_FOR']
, make sure you also save the
$_SERVER['REMOTE_ADDR']
value. E.g. by saving both values in different fields in your database.


So I'm changing my code to this:

$remote_add = $_SERVER['REMOTE_ADDR']; // I don't use isset() for this becase it is always set
$http_x_forwarded_for = isset( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : null;

// IPs
+----+----------------+----------------+-------------+
| id | remote | forwarded | date_time |
+----+----------------+----------------+-------------+
| 1 | 43.12.9.9 | NULL | 1468070172 |
| 2 | 93.35.40.1 | 173.3.0.1 | 1468070667 |
+----+----------------+----------------+-------------+





Ok what I'm doing is correct? I'm asking this because a few professional programmers tell me what you doing is useless and you need just on column as user's IP. Well may please someone clear me up? How can I get user's IP correctly?




My final code:

foreach (array('HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED') as $key){
if (array_key_exists($key, $_SERVER) === true){
foreach (explode(',', $_SERVER[$key]) as $header){
$header = trim($header); // just to be safe
if (filter_var($header, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) !== false){
$header = $header;
}
}
}
}

$user_ip = $_SERVER['REMOTE_ADDR'];

// IPs
+----+----------------+----------------+-------------+
| id | user_ip | header | date_time |
+----+----------------+----------------+-------------+
| 1 | 43.12.9.9 | NULL | 1468070172 |
| 2 | 93.35.40.1 | 173.3.0.1 | 1468070667 |
+----+----------------+----------------+-------------+

Answer

In a http-request, someone can spoof ANY information, except for the remote address. You cannot complete the tcp handshake without actually having access to the modem on that ip-address, or a computer behind that modem/router. The REMOTE_ADDR key is always set to the device that made the connection to your server. In some cases that device is the proxy that was used by the user.

The HTTP_X_FORWARDED_FOR header is a header that nice proxies use to signify what the originating ip-address was that ordered the proxy to load a page on their behalf. This header can however be spoofed. Someone can send any information in this header, including fun things such as 127.0.0.1 (localhost), or even html or scripts for servers that just assume that field can only contain numbers and dots, or even raw sql statements for servers that do not use prepared queries to insert this stuff.


The only information that is guaranteed correct is the remote ip, but it is not necessarily the user's ip. If the remote ip is a proxy, logging the remote ip might allow you to contact the owner of the remote proxy of fraudulent behaviour, to let them search their logs which ip actually made that request. The forwarded ip can in some cases safe you time in cases where the proxy was not intended to obscure the identity of the person that used the proxy, which would allow you to take some measures against that ip, instead of the proxy itself.

Making an educated guess, by sometimes using the HTTP_X_FORWARDED_FOR header and sometimes using the REMOTE_ADDR, will result in unusable data. You can not know which data you can trust, and which data you can not trust.

I'm asking this because a few professional programmers tell me what you doing is useless and you need just on column as user's IP.

If what you are doing is useless depends completely on what you are using this for. If you are displaying the forwarded field, remember to properly escape all special characters for the context in which you display it. If you would only store one ip, it would be the remote ip, ignoring the HTTP_X_FORWARDED_FOR header completely. It is the only information you can completely trust.