Work In Progress

This book is currently work in progress. Some sections are not yet written. Thank you for your understanding!

DON'T: Using REMOTE_ADDR to get the user's IP

It is very common for extensions to need access to the user's IP address. I see extensions doing silly things like this:

$ip = $_SERVER['REMOTE_ADDR'];
$ip = $this->input->server->get('REMOTE_ADDR');

DO NOT DO THAT; THIS IS WRONG ON MANY LEVELS!

The first line tries to access the $_SERVER superglobal which, as mentioned in the previous section, is a security issue waiting to happen.

Both of these lines make a wrong assumption: that the REMOTE_ADDR key of the server superglobal array will contain the user's IP address. This is not true if the server is behind a load balancer, CDN, firewall or any other kind of non-transparent proxy. In these cases a different HTTP header —typically X-Forwarded-For— may be used to convey the forwarding chain of IP addresses. However, you should NOT attempt to read this header yourself for two reasons. First of all, if the site is not behind a non-transparent proxy a malicious actor can send a forged X-Forwarded-For header to trick your extension into believing the request came from a different IP address than the one it actually originates. Second, this header may contain more than one IP address in a comma-separated list. Validating, sanitizing and parsing that list is tricky and may lead to some very bad times and security issues.

Joomla 3.10 and later (including all 4.x releases and beyond) include a fork of my IPHelper class which deals with all of these details automatically. They also expose user-facing options in the Global Configuration so that the site owner can inform Joomla whether their site is behind a non-transparent proxy server.

You can get the real IP address of the user with this:

$ip = \Joomla\Utilities\IpHelper::getIp();

Even better, going through the IpHelper makes your code testable. Your unit tests can simply call:

\Joomla\Utilities\IpHelper::setIp('1.2.3.4');

to set a fake IP address of your choice (IPv4 or IPv6).

Finally, IpHelper has two more handy methods: isIPv6 which tells you if you are dealing with an IPv6 address and IPinList which lets you figure out if an IP address is contained in an array which consists of any combination of IPv4/IPv6 addresses, IPv4 ranges (e.g. 1.2.3.4-1.2.3.255), IPv4/IPv6 subnets in CIDR notation (e.g. 1.2.3.4/24) or IPv4 subnets in IP/Netmask notation (e.g. 192.168.1.0/255.255.255.0). Since many use cases for getting the user's IP address ultimately come down to checking if it belongs in a range of IP addresses or a list of allowed/blocked IP addresses you'll find the latter method extremely handy. I went through the pain of figuring out IP address maths and Joomla included my work in the core so you don't have to deal with it yourself!