Considering the current implementation: https://github.com/matomo-org/matomo/blob/a31fd86b64c2c7d2deadcfca71540fb4b0152c10/core/IP.php#L99-L125
With the following setup:
[client] -> [reverse proxy 1] -> [reverse proxy 2] -> [matomo Nginx]
Since each proxy appends the IP of the incoming connection according to RFC7239,
X-Forwarded-For will be this by the time the connection reaches Nginx (1):
X-Forwarded-For: (client), (proxy 1)
Matomo currently extracts the first IP from the list, since #10404. This is correct until you realized the "client" can pretended to be a proxy as well, by including its own
X-Forwarded-For header, like this:
curl -i -H"X-Forwarded-For: 184.108.40.206" "http://example.com/matomo/matomo.php?..."
When this happens, proxy 1 will be faithfully preserve the header passed in and append the client IP after it (2):
X-Forwarded-For: 220.127.116.11, (client), (proxy 1)
And Matomo will extract
18.104.22.168 as the client IP.
If Matomo decided the first "client" IP can always be trusted, we can still extract the first IP address, and this issue can be closed as "works as intended." But it will in risk of having the analytics data being polluted. Brutal force login detection can be tricked too.
This would involve reverting #10404 and go back to extract the last IP address. Since the original
proxy_ips configuration is still intact, when facing a header like (2), above, a correctly configured Matomo will be able to exclude the "proxy 1" IP address.
HTTP_CLIENT_IP, etc) behaves and if Matomo have to do things differently between these and the
proxy_ipspretty well in the documentation. We may consider doubling down on the documentation effort when we pick either solution for this issue.
IP::getFirstIpFromListbut it didn't change the word "last" in the function comment right above it :)
Hi @timdream, thanks for creating this issue. Is this behavior in Matomo causing a problem for you specifically? Do you know of a client that does this and is causing a problem?
@diosmosis It did not cause a problem for me! I am just trying to document what I've found that may be problematic in terms of spoofing and attack vector. I did not spot such attack/spoofing taking place on my own instance.
@tsteur Yes the issue is related (see note), but I wouldn't say it is a duplicate because the research I made here contains new information on the current implementation.
There can be a solution 1.1 where Mamoto will rely on proxy 1 (the first public-facing proxy) to remove the spoofed header. However this is not always possible (not possible for Apache AFAIK)
that was my first thought would be the preferred solution as AFAIK in https://github.com/matomo-org/matomo/pull/10404 it says
The RFC at https://tools.ietf.org/html/rfc7239 makes it clear that we should extract the first IP from the header HTTP_X_FORWARDED_FOR
So changing it to last IP could potentially break things again etc.
Another workaround might be to use other headers depending on what can be configured that can only be set by the public facing proxy? I don't know if that's the same problem for Apache.
Mostly seeing this so far as a documentation issue to mention it in the docs for setting up the proxy if it's not mentioned yet.