How PHP populates $_SERVER['REMOTE_ADDR'] with client IP address? - php

I have a PHP application in front of me that reads the IP address of the user from $_SERVER['REMOTE_ADDR'].
I don't seem to quite understand how it gets populated. I assume that it is basically reading the client IP address from the request headers. Is that correct?
Note:
I am not asking about whether it is providing the client IP address or not. The documentation already states that fact. I am more interested in the knowing about the "how". Is it retrieving the IP address implicitly from the request headers?

Not a network expert in any way, but as it's an HTTP request, it gets delivered over a TCP connection. The webserver populates $_SERVER['REMOTE_ADDR'] from a TCP socket that is used to communicate with the browser.

Related

Is $_SERVER['REMOTE_ADDR'] secure?

I'm working on a API project that depends partialy from $_SERVER['REMOTE_ADDR'] (like 50%).
My API checks the IP of client first and then checks the token, and i want to know if should i worry about getting this IP from this global variable.
can the client some how "forge" this?
i know that VPN can camouflage the IP, but thats not a problem since he will not getting access anyway.
Due to the three way handshake of TCP/IP - $_SERVER['REMOTE_ADDR'] cannot be spoofed. There is (however) no guarantee that this is the IP address of the end user. He may be behind proxy or VPN. What you can guarantee with $_SERVER['REMOTE_ADDR'] is that the machine which is directly connected to you has this exact IP and it is real.

Can we spoof $_SERVER['REMOTE_ADDR'] / user ip with php cURL?

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?

How i change my ip address to a given address and access a website

How to change ip address such that it does not reveal our original address when using $_SERVER['REMOTE_ADDR']; in php
You need to use a proxy server if you're trying to access a website from a different IP than your own. Wikipedia has more information.
There are several options I have in mind for this. I will go from the simpler to the more complicated one.
First, you could use a proxy server and ask him through an HTTP request made by your program or your browser, to fetch a resource for you. The proxy server will take the role of querying a resource in your place to the target service.
Example :
You want to retrieve the main page of the domain stackoverflow.com. You ask the proxy server to ask stackoverflow's HTTP server to send him the main page and he will forward it back to you.
To SO webserver, the superglobal $_SERVER['REMOTE_ADDR'] variable will correspond to the proxy server's IP address and not yours. However, the HTTP protocol implements some fields such as HTTP_VIA, HTTP_X_FORWARDED_FOR, or HTTP_FORWARDED which can be used to know if the current HTTP request is made by a proxy or not.
A transparent proxy will not specify those fields and will not modify your request whereas a non-transparent proxy may reveal the original IP address of the original requester. You got to use a reliable proxy which will act as you intends it to act. Another thing to consider is the use of an SSL tunnel between you and the proxy to avoid eavesdropping.
The second solution is to use a VPN (Virtual private network) server. It would be too complicated to fully explains how this works, but remember this, when you are connected to a computer using a VPN service (like l2tpd, pptpd ...) it's like you were on the same LAN with this computer. So you can transparently make requests to a webserver and he will never find out what's your real IP address.
A third solution could be to use linked nodes based network such as TOR. It's a free network you can connect to, and you will be completely anonymous to regular people. The TOR network power is to provide a network of many nodes and each nodes doesn't know anything about other nodes, so even people connected to the TOR network cannot know anything about you. I suggest you to read more about this if you're interested.
There are more complicated other solutions such as TCP session hijacking which is generally used to fake IP addresses and literally steal another computer's TCP connection, but this is out of the scope of this answer.

How to fake $_SERVER['REMOTE_ADDR'] variable?

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

Detect forged IP address?

How do you detect if the IP address for data received via a web form has come from a spoofed IP address?
If detection is possible in PHP, is there a library that will also attempt to find the real IP address?
Äh - you can not. There can not be a spoofed IP address.
See, HTTP (which is the b asis for web forms) runs on top of TCP.
If I spoofe my IP address in the TCP process, I will never manage to establish the TCP connection. WIthout an established TCP connection, I can not send any data to your server.
THe connection on your side keeps stuck in a half open state - which, btw., was one of the attack vectors some time ago for a denial of service attack (overloading servers with half open connections so real ones do not get established):
Ergo: In order to complete the form data submission, I need to open the TCP channel, for which my IP packets need to provide the real IP address.
Where did you get the idea that your submissions come from spoofed IP addresses?

Categories