To obtain the client IP address in my ASP.NET application I've used the X-Forwarded-For, and get the first IP address from the list (accordingly to the information I've found, there is a client, proxy1, proxy2..). But I've heard recently that it is better to get this information from X-Forwarded-IP header because the client IP address in X-Forwarded-For can be modified by proxy, what is the difference, and which one address should I use?
X-Forwarded-For is the conventional way of identifying the originating IP address of the user connecting to the web server coming from either a HTTP proxy, load balancer.
X-Forwarded-IP is the conventional way of identifying the originating IP address of the user connecting to the email server through an HTTP mail service.
X-Forwarded-For is a non-standard header, introduced originally by Squid. It is a proxy- specific header, that helps a server identify the original requestor of a call that did pass-through the proxy - so obviously any proxy on the request path should/will modify X-Forwarded-For. Without proxy on the request path, this header shouldn't even be in the request.
Because this header is non-standard, there is no guarantee you'll get it, and the way it is handled can differ on the proxy implementation. You have no guarantee either that it will contain a proper IP.
Since 2014, the IETF has approved a standard header definition for proxy, called "Forwarded", documented here https://www.rfc-editor.org/rfc/rfc7239 that should be use instead of X-Forwarded headers. This is the one you should use reliably to get originating IP in case your request is handled by a proxy.
In general, the proxy headers (Forwarded or X-Forwarded-For) are the right way to get your client IP only when you are sure they come to you via a proxy. If there is no proxy header or no usable value in, you should default to the REMOTE_ADDR server variable.
Related
I have used the below code from link to detect the browser is TOR or not.
Code
But when the server is hosted on AWS, we didn't get the exact $_SERVER['SERVER_ADDR'] as the AWS is providing the private ip of machine or load balancer ips.
So is there any way to detect the AWS private ips from the TOR exit list to detect whether the user is using the TOR browser or not.
First to make that code work properly, you have to get the actual client IP. That data in sent to your client via the x-forwarded-for header:
From HTTP Headers and Classic Load Balancers:
The X-Forwarded-For request header helps you identify the IP address
of a client when you use an HTTP or HTTPS load balancer. Because load
balancers intercept traffic between clients and servers, your server
access logs contain only the IP address of the load balancer. To see
the IP address of the client, use the X-Forwarded-For request header.
Elastic Load Balancing stores the IP address of the client in the
X-Forwarded-For request header and passes the header to your server.
For more information on how to detect Tor exit nodes, see Tor DNS Exit List:
It is useful for a variety of reasons to determine if a connection is
coming from a Tor node. Early attempts to determine if a given IP
address was a Tor exit used the directory to match IP addresses and
exit policies. This approach had a number of drawbacks, including
false negatives when a Tor router exits traffic from a different IP
address than its OR port listens on. The Tor DNS-based Exit List was
designed to overcome these problems and provide a simple interface for
answering the question: is this a Tor exit?
I've read that is is possible that a client doesn't send an IP-Address on requesting. So I would prevent that a user can access to my page without giving an IP-Address.
For the case the IP-Adress is not sent, which value has $_SERVER['REMOTE_ADDR'] (PHP)? May null, "", or 0.0.0.0?
There is always an IP, however when you have several layers of software the original IP can be lost on its way to PHP unless the software is configured correctly.
It's not uncommon to have a setup stack with Varnish > Nginx > PHP-FPM, where responds to the original request (and get the visitor IP) and then in turn contacts the web server (nginx) which in turn calls PHP-FPM. In all of these "forwards" each software must be configured to include the original IP in headers or otherwise.
This is what the HTTP headers X-Real-IP and X-Forwarded-For are used for.
(Nginx and other software has configuration directives and modules to help with the specific scenario I mentioned above.)
I have the following scenario. A person makes a request to my server, a controller handles this request. Inside this controller code I have a logic that makes another GET request to some endpoint. Is it possible to have/make the request to this GET endpoint on behalf of this person's IP address (use it as a proxy) instead of the server's IP address ??
If your server is making this request, server IP will be used, this is legit. As for http, you can use x-forwarded-for header to point recipient that your server is used like proxy for client.
Another solution is to force client to make this request via some sort of callbacks.
Well the title basically says it.
But for more info . .
This method works but . .
$ip = '1.1.1.1';
curl_setopt($handle, CURLOPT_HTTPHEADER, array("REMOTE_ADDR: $ip", "X_FORWARDED_FOR: $ip"));
It only adds these two keys on the $_SERVER array
HTTP_REMOTE_ADDR
HTTP_X_FORWARDED_FOR
The key REMOTE_ADDR still remains the same.
Can REMOTE_ADDR be changed? The answer here says NO. But a comment also says It may, however, NOT be the user's real IP address because it may be hidden by proxies and other methods. That is why the general rule is to not depend on $_SERVER['REMOTE_ADDR'] for a security feature.
With all that aside is there a curl php method to also hide/mask/change the ip? (any other php method aside from the above code would do.)
AND
Is there a way for countering the method OR Is there a way to get the ACTUAL REAL IP of a user?
Cheers!
No. $_SERVER['REMOTE_ADDR'] is the actual physical IP address the client used to connect to the webserver, as confirmed by a three-way TCP handshake. There's no way to fake this by setting simple HTTP headers. You also cannot make the webserver/PHP overwrite this value with something else in any way. $_SERVER['REMOTE_ADDR'] is set from TCP connection information, period.
To actually spoof an IP address, you have to go much deeper into the actual network layer and have some level of control over network equipment/man in the middle positions/proxies/whatnot to actually be able to establish a TCP connection from an IP address other than the one you're establishing it from.
Is there a way for countering the method OR Is there a way to get the ACTUAL REAL IP of a user?
No. "The actual IP address of the user" is the address your webserver received the connection from, period. There is no other address for you. The client connects to your server from a certain IP, this is confirmed with a three-way TCP handshake, that's the only address you know for this client. This client may be a proxy or a NAT router (i.e. a proxy) or something else, you simply do not know and neither should it make any difference to you.
If the client uses a browser behind a proxy, the $_SERVER['REMOTE_ADDR'] will be the IP address of the proxy. The remote address is the IP of the machine that is making the connection.
If the proxy uses headers to indicate if the connection is performed in behalf of other machines, you can use these headers to determine the IP of the browser behind the proxy.
Some of these HTTP headers are converted to environment variables such as $_SERVER['HTTP_X_FORWARDED_FOR'], $_SERVER['HTTP_X_FORWARDED'], $_SERVER['HTTP_FORWARDED_FOR'] and $_SERVER['HTTP_FORWARDED']
You may check if some of these variables have been defined by the server and (try to) determine the IP of the browser behind of the proxy.
Note that the RFC 6648 deprecated the X-* headers and the RFC 7239 deprecated X-Forwarded-* by defining a Forwarded header.
You can check some answers at
Get the client IP address using PHP
What is a full specification of X-Forwarded-Proto HTTP header?
Is it possible to fake or hijack a content of $_SERVER['REMOTE_ADDR'] variable?
I would like to fake a request with:
$_SERVER['REMOTE_ADDR']='127.0.0.1';
How could I do that with PHP? Can CURL do that somehow?
I assume that you mean faking it remotely. The short answer is yes you can. The long answer about how easy it is depends on how you want to fake it.
If you don't care about receiving a response, it's as trivial as opening a raw socket to the destination and forging the source IP address. I'm not sure if it's really easy to do in PHP since all of PHP's socket implementations are at or above the TCP level. But I'm sure it's possible. Now, since you're not in control of the network, the response will not go back to you. So that means that you cannot (reliably anyway) create a TCP connection via a trivial forged TCP header (since the syn-ack does prevent this by requiring two-way communication).
However, if you can compromise the gateway the IP is off of, you can do whatever you'd like. So if you compromise the wifi router a computer is connected to, you can pretend to be that computer, and the server won't tell the difference. If you compromise the ISP's outbound router, you can (in theory at least) pretend to be the computer and the server won't tell the difference.
For some more info, see these following links:
ServerFault Question
Symantec Article
Linux Security Article
However, you will only be able to forge the 127.0.0.1 loopback address under TCP if you actually compromise the local machine/server. And at that point does it really matter?
Important
If you're using a framework to access this information, be absolutely sure that it does not check the X-HTTP-FORWARDED-FOR header! Otherwise it's trivial to fake the IP address. For example, if you're using Zend Framework's Zend_Controller_Request_Http::getClientIp method, be absolutely sure that you pass false as the parameter! Otherwise someone just needs to send an HTTP header: X-Http-Forwarded-For: 127.0.0.1 and they now appear to be local! This is one case where using a framework without understanding how it works in the backend can really be bad...
Edit: Relevant
I wrote a blog post recently about how I stumbled across a vulnerability in StackOverflow's application. It's very relevant here, since it exploits a very similar mechanism to what this question is looking for (although the circumstances around it are somewhat narrow):
How I Hacked StackOverflow
The remote address is not something added out of courtesy, it's used in the IP protocol to route packages, so if you send a package with a fake address, you will not receive a response, and since you're talking about a HTTP request, which is delivered over a TCP connection, which takes several IP packets (and the matching responses) to set up:
No, that's impossible (except of course by actually sending the request from the same host via the loopback interface).
Apache populates $_SERVER['REMOTE_ADDR'] from a TCP socket that it uses to communicate with your browser. It is IMPOSSIBLE to influence this variable over the open internet because of the three-way-handshake. If the client and the server is on a broadcast network, like wifi, then you can sniff the wire and complete the handshake.
If you browse via a proxy, $_SERVER['REMOTE_ADDR'] may be set to the proxy's IP address rather than the end user's.
There are other headers which you can use instead in this case: This page gives a function which checks all the possibilities and provides the address most likely to be the end user's:
http://roshanbh.com.np/2007/12/getting-real-ip-address-in-php.html
However if the user is proxying using a badly configured proxy, or a malicious one, or one designed to anonymise the end user, then you won't be able to guarantee any of the headers other than REMOTE_ADDR (which would only lead you as far as the proxy).
If your end user is browsing via HTTPS, then REMOTE_ADDR will always be his IP address; you can't use proxy forwarding via HTTPS. Therefore, the one way to be absolutely sure of his address is to get him to open your site in HTTPS.
You can overwrite any item in the $_SERVER array, including the one you mention, in your server; of course, not in someone else's.
However, it won't change your computer's IP address.
REMOTE_ADDR
The IP address from which the user is viewing the current page.
You can request script using proxy, etc. to change IP address but you cannot set there any text you want.
That is a variable set by apache or whatever server you're using. You cannot spoof it.
You may run $_SERVER['REMOTE_ADDR']='127.0.0.1'; at the beginning of the scripts, but i doubt thats what you're trying to do