News:

Support the VirtueMart project and become a member

Main Menu

Incorrect customer IP if the website uses CloudFlare

Started by man.of.earth, December 11, 2019, 21:06:06 PM

Previous topic - Next topic

man.of.earth

Hello developers,

I noticed that customer IPs are not returned correctly using $_SERVER['REMOTE_ADDR'] if the VM website uses CloudFlare (this instruction returns the IP of the CloudFlare nearest mirror of the VM website).
Fortunately, CloudFlare adds two headers with the original customer IP: $_SERVER['HTTP_X_FORWARDED_FOR'] and $_SERVER['HTTP_CF_CONNECTING_IP'] (and $_SERVER['HTTP_TRUE_CLIENT_IP'] if it's the Enterprise paid plan).
$_SERVER['REMOTE_ADDR'] is used in the following files:
/com_virtuemart/administrator/components/com_virtuemart/helpers/shopfunctions.php
/com_virtuemart/administrator/components/com_virtuemart/models/orders.php

and in the following plugins:
istraxx_downloader_simple.php
eway.php
heidelpay.php
heidelpay_response.php
klarna.php
paypal.php


A remedy to this would be a conditional fallback on which header can be used, something like
if (isset($_SERVER['HTTP_TRUE_CLIENT_IP'])) $ip = $_SERVER['HTTP_TRUE_CLIENT_IP']; # CloudFlare specific header for enterprise paid plan, compatible with other vendors
elseif (isset($_SERVER['HTTP_CF_CONNECTING_IP'])) $ip = $_SERVER['HTTP_CF_CONNECTING_IP']; # another CloudFlare specific header available in all plans, including the free one
elseif (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) $ip = $_SERVER['HTTP_X_FORWARDED_FOR']; # specific header for proxies
elseif (isset($_SERVER['REMOTE_ADDR'])) $ip = $_SERVER['REMOTE_ADDR']; # this one would be used, if no header of the above is present

man.of.earth

#1
Hello developers,

Regarding the matter of determining the client IP, I also found some mistaken headers in /administrator/components/com_virtuemart/helpers/shopfunctions.php , line 1503:
static function getClientIP() {
$ip_keys = array('X_FORWARDED_FOR', 'X-Forwarded-Proto','REMOTE_ADDR');


The correct headers are HTTP_X_FORWARDED_FOR (instead of X_FORWARDED_FOR) and HTTP_X_FORWARDED_PROTO (instead of X-Forwarded-Proto).
Another thing is that the HTTP_X_FORWARDED_PROTO header returns ,,https" or ,,http", and not an IP (it is used in a loop, in the following lines from that file, where IPs are concerned).
This can be corrected together with the CloudFlare headers problem described above, so the second line could become
$ip_keys = array('HTTP_TRUE_CLIENT_IP', 'HTTP_CF_CONNECTING_IP', 'HTTP_X_FORWARDED_FOR', 'REMOTE_ADDR');
Of course, there are other places where this would have to be changed, in order to determine the real IP of the client - in /administrator/components/com_virtuemart/models/orders.php , on line , the IP of the client is taken directly from REMOTE_ADDR header,
$_orderData->ip_address = $_SERVER['REMOTE_ADDR'];
instead of calling the getClientIp function, where this header problem could be resolved (for efficiency, being in one place, rather than several places).