I have a competition scripted in PHP, vote based. From one IP, one person can vote for someone one time. I have a log of all IP addresses that voted, but I see something strange. Some IP addresses appear to be like for="ip_address:port", while others are just ip_address, and I see that one ip address, formatted with for="..." appear to be there multiple times, just with different ports. Can someone please explain it to me? How users do this, should I ban them from competition for this?
I use this function to get user IP address:
function get_client_ip_env() {
if (getenv('HTTP_CLIENT_IP'))
$ipaddress = getenv('HTTP_CLIENT_IP');
else if(getenv('HTTP_X_FORWARDED_FOR'))
$ipaddress = getenv('HTTP_X_FORWARDED_FOR');
else if(getenv('HTTP_X_FORWARDED'))
$ipaddress = getenv('HTTP_X_FORWARDED');
else if(getenv('HTTP_FORWARDED_FOR'))
$ipaddress = getenv('HTTP_FORWARDED_FOR');
else if(getenv('HTTP_FORWARDED'))
$ipaddress = getenv('HTTP_FORWARDED');
else if(getenv('REMOTE_ADDR'))
$ipaddress = getenv('REMOTE_ADDR');
else
$ipaddress = 'UNKNOWN';
return $ipaddress;
}
Also, if anyone know some good reference and manual with all predefined variables in PHP, please share it with me.
IP addresses HTTP headers can easily be spoofed and a lot of users (mainly mobile users on for example a wifi connection) have lease times on IP addresses that are very short, thus enabling them to vote again.
That said you can combine options, for example check IP address and set a cookie to make it harder to get around.
If you set a port with the ip address then it will not match your database records/list of IP addresses. Should you ban them for that? I can't answer that.
Most of your checking method is based on what the request says is the IP address, like the HTTP headers, which are easily spoofed. Don't trust them or accept that your poll is not going to get accurate results.
If you really want a fair voting system that allows one vote per person you will need to use something else then IP address to identify the user.
try this, it may helpfull for you
<?php
//for example
$ip = "216.58.196.68:8989";
$ip = strstr("$ip",':',true); //get text before :
echo $ip;
//it echo only 216.58.196.68
?>
Related
I am trying to code a PHP script for getting the client's IP address using this function:
public function getIpAddress() {
$ipAddress = '';
if (! empty($_SERVER['HTTP_CLIENT_IP']) && $this->isValidIpAddress($_SERVER['HTTP_CLIENT_IP'])) {
// check for shared ISP IP
$ipAddress = $_SERVER['HTTP_CLIENT_IP'];
} else if (! empty($_SERVER['HTTP_X_FORWARDED_FOR']) && $this->isValidIpAddress($_SERVER['HTTP_CLIENT_IP'])) {
// check for IPs passing through proxy servers
// check if multiple IP addresses are set and take the first one
$ipAddressList = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
foreach ($ipAddressList as $ip) {
if ($this->isValidIpAddress($ip)) {
$ipAddress = $ip;
break;
}
}
} else if (! empty($_SERVER['HTTP_X_FORWARDED']) && $this->isValidIpAddress($_SERVER['HTTP_X_FORWARDED'])) {
$ipAddress = $_SERVER['HTTP_X_FORWARDED'];
} else if (! empty($_SERVER['HTTP_X_CLUSTER_CLIENT_IP']) && $this->isValidIpAddress($_SERVER['HTTP_X_CLUSTER_CLIENT_IP'])) {
$ipAddress = $_SERVER['HTTP_X_CLUSTER_CLIENT_IP'];
} else if (! empty($_SERVER['HTTP_FORWARDED_FOR']) && $this->isValidIpAddress($_SERVER['HTTP_FORWARDED_FOR'])) {
$ipAddress = $_SERVER['HTTP_FORWARDED_FOR'];
} else if (! empty($_SERVER['HTTP_FORWARDED']) && $this->isValidIpAddress($_SERVER['HTTP_FORWARDED'])) {
$ipAddress = $_SERVER['HTTP_FORWARDED'];
} else if (! empty($_SERVER['REMOTE_ADDR']) && $this->isValidIpAddress($_SERVER['REMOTE_ADDR'])) {
$ipAddress = $_SERVER['REMOTE_ADDR'];
}else{
$ipAddress = 'error';
}
return $ipAddress;
}
I tried it many times and it's working. But I tried to connect to a VPN and it retrieved IPv6 instead of IPv4!
This could be a normal situation but I need to get the IPv4 of the visitor of that PHP script.
I googled a lot about converting IPv6 to IPv4 and I know that it cannot be converted.
But I notices some IP geolocation services are retrieving IPv4 for the same VPN (on the same device)! For example: canyouseeme.org and api.ipify.org.
That's mean that even if the IPv6 cannot be converted into IPv4, there's a method can be implemented to get IPv4 even if the visitor is using IPv6!
My questions:
If the conversion is not possible between these two versions, how did these IP geolocation services retrieved the IPv4 of the visitor?
If they are not converting the IPv6 into IPv4. So, they are retrieving the IPv4 directly without touching the IPv6. But, how did they do that if the $_SERVER does not contain an IPv4?
In additional to that, I noticed that when I visited whatismyipaddress.com, they retrieved the IPv6 first then it start loading beside the IPv4 field then they retrieved it!
Note: All these sites has retrieved the same IPv4.
Thanks.
Just drop the AAAA record from your DNS name (or disable ipv6 in your webservrr - this might introduce delays as browsers are supposed to prefer ipv6), then, however, people w/o ipv4 cannot access your service any more. As #MagnusEriksson said: "Instead of fighting the future, wouldn't it be better to fix your application so it works with IPv6 as well?"
Also, please be aware, if the ip address is so important for you, that http headers can be easily spoofed by clients (i.e., don't trust user provided data) or proxy servers might provide private ips as defined in RFC1918. You should only consider/use the headers you know a trusted proxy infront of your server uses - in all other cases you cannot trust the user provided headers.
if you are using apache, you may want to check if there are any IPv6 Bindings or VirtualHosts. there will be similar settings for other web servers
if you don't have access to the web server config, you can see if there's an option to disable IPv6 in your webhost panel
also, this could be client-controlled, i.e. when you connect using a VPN then IPv6 is enabled for that network interface (or tunnel). in which case you cannot force the visitor to disable IPv6 on their device / router, but you could try to disable it on your end. unlike HTTPS Everywhere which only accepts port 443 or nothing, I don't think IP addresses are at the stage where it is only possible to accept IPv6 with no fallback to IPv4, so this recommendation should be safe
I'm trying to create a php counter, and in order not to count repeated visits from the same visitor, I've been thinking about saving the visitor's IP address into the database, and I should turn to $_SERVER
I've read this sample funtion by #Dusza that seems nice and convenient:
<?php
function get_IP() {
// ADDRESS IP
if (getenv('HTTP_CLIENT_IP')) $ipaddress = getenv('HTTP_CLIENT_IP');
else if(getenv('HTTP_X_FORWARDED_FOR')) $ipaddress = getenv('HTTP_X_FORWARDED_FOR');
else if(getenv('HTTP_X_FORWARDED')) $ipaddress = getenv('HTTP_X_FORWARDED');
else if(getenv('HTTP_FORWARDED_FOR')) $ipaddress = getenv('HTTP_FORWARDED_FOR');
else if(getenv('HTTP_FORWARDED')) $ipaddress = getenv('HTTP_FORWARDED');
else if(getenv('REMOTE_ADDR')) $ipaddress = getenv('REMOTE_ADDR');
else $ipaddress = 'UNKNOWN';
//return $ipaddress;
}
?>
But I've done some research here, and found that there's a security hole in that because the user can spoof all values except REMOTE_ADDR, which can be modified by a proxy.
So I guess that when they say that there's a security hole, it means that I should sanitize the user's input when I insert it into the database doing some bindings.
Is there any other precaution?
Given that all other values are unreliable I should avoid using them altogether?
But what about the un-spoffing value of REMOTE_ADDR? That can be modified by a proxy.
Any suggestions on what path should I take?
If you want to downvote, or vote the question to be closed or deleted, please leave
me a comment about why, so I can improve my questions. Thanks.
REMOTE_ADDR is the IP address established through a 3-way TCP/IP handshake. It is the IP the response will be sent back to. It is the only thing that your server has verified. Everything else is just arbitrary HTTP headers anyone could set.
Now, if you know that your server is running behind a proxy (e.g. a load balancer) which would mask the visitor's IP address (your server would only see the proxy's IP), but you know that the proxy is helpfully forwarding you the visitor's IP in an HTTP header (as workaround for this situation so your server can still see the visitor's IP), then and only then may you use one of these HTTP headers and only the one that you know your proxy is setting. If your server is not behind a proxy, use REMOTE_ADDR exclusively. Otherwise, consult your proxy's manual and implement according to the situation.
I want to browse some sites using a proxy, so I want to change the IP address of my client to the specified IP.
I am also testing it on localhost, so my goal is to visit my localhost site with PHP script (also localhost). The problem is how to test this (maybe some simple test by writing out changed IP to file).
I'm not entirely sure what exactly you mean, but you can check your clients IP address with this:
if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
$ip = $_SERVER['HTTP_CLIENT_IP'];
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
} else {
$ip = $_SERVER['REMOTE_ADDR'];
}
echo $ip;
Ofcourse this will not change your clients IP address. You need an actual proxy server for that.
This question already has answers here:
How to get the client IP address in PHP
(32 answers)
Closed 8 years ago.
I've been trying to get real IP address of the user, and not a proxy address. For that I've done this:
$ip1 = $_SERVER['REMOTE_ADDR'];
$ip2 = $_SERVER['HTTP_X_FORWARDED_FOR'];
$ip3 = $_SERVER['HTTP_FORWARDED'];
mail("me#domain.com", "Report", "IP1 is $ip1, IP2 is $ip2, IP3 is $ip3 .");
But when a user is using proxy, the above script gets the proxy address and not the real IP address:
IP is [proxy_addr_here], IP2 is , IP3 is .
Is there any way to get real IP just like whatismyip.com tells (it tells real IP address, proxy address and useragent)?
Update : Whatismyip tells me this
"Your IP Address Is: [my real IP]
Proxy: [my proxy address]
City: Alipur
State/Region: Delhi
Country: IN -
ISP: Bharti Airtel Ltd."
How come it gathers all the details so accurately but not my PHP script?
You could do
$ip= isset($_SERVER['HTTP_X_FORWARDED_FOR']) ?
$_SERVER['HTTP_X_FORWARDED_FOR'] : $_SERVER['REMOTE_ADDR'];
But even that is not 100%. Getting IP of the real user now a days is not a guarantee with so many NAT firewalls in between, let alone proxies.
Edit
To answer your edit as to how they show you more information, you could use many features of the language to get more request details. For example try
print_r(getallheaders());
Then you can also use
print_r($_SERVER);
And extract the required information from there.
Edit 2
Even your favorite whatismyip.com reports
Your IP Location can be found using our IP Lookup tool. No IP Lookup tool is 100% accurate due to many different factors. Some of those factors include where the owner of the IP has it registered, where the agency that controls the IP is located, proxies, cellular IPs, etc. If you are in the US and the controlling agency of the IP is located in Canada, chances are the IP address lookup results will show as Canada. Showing a Canadian IP while in the US is very common among Blackberry users on the Verizon network.
Reference
You might still ask ok then why cant I get at least what they show? Im sure they have put up a lot of research and resources in setting up that tool, its not a one line PHP code, in fact there is no telling whether that site is written in PHP at all. Some more research and you will be on your way to try to match their lookup.
You can try this...
<?PHP
function getUserIP()
{
$ipaddress = '';
if (getenv('HTTP_CLIENT_IP'))
$ipaddress = getenv('HTTP_CLIENT_IP');
else if(getenv('HTTP_X_FORWARDED_FOR'))
$ipaddress = getenv('HTTP_X_FORWARDED_FOR');
else if(getenv('HTTP_X_FORWARDED'))
$ipaddress = getenv('HTTP_X_FORWARDED');
else if(getenv('HTTP_FORWARDED_FOR'))
$ipaddress = getenv('HTTP_FORWARDED_FOR');
else if(getenv('HTTP_FORWARDED'))
$ipaddress = getenv('HTTP_FORWARDED');
else if(getenv('REMOTE_ADDR'))
$ipaddress = getenv('REMOTE_ADDR');
else
$ipaddress = 'Unknown IP Address';
return $ipaddress;
}
$user_ip = getUserIP();
echo $user_ip; // Output IP address (Ex: 123.345.456.678)
?>
I have PHP code that is supposed to detect a user's IP address. The code below returns an IP address, but the IP address is sometimes a local network IP (e.g. 10.0.0.1) and not a public IP. How can I ensure that I always get the public IP? Thanks. BTW, this code is from another StackOverflow post. Also, this code is used in a website that is being accessed over the internet from a completely separate network than that of my Apache web server.
if (isset($_SERVER["HTTP_CLIENT_IP"])){
$ip = $_SERVER["HTTP_CLIENT_IP"];
} elseif (isset($_SERVER["HTTP_X_FORWARDED_FOR"])){
$ip = $_SERVER["HTTP_X_FORWARDED_FOR"];
} elseif (isset($_SERVER["HTTP_X_FORWARDED"])){
$ip = $_SERVER["HTTP_X_FORWARDED"];
} elseif (isset($_SERVER["HTTP_FORWARDED_FOR"])){
$ip = $_SERVER["HTTP_FORWARDED_FOR"];
} elseif (isset($_SERVER["HTTP_FORWARDED"])){
$ip = $_SERVER["HTTP_FORWARDED"];
} else {
$ip = $_SERVER["REMOTE_ADDR"];
}
Eliminate all the if(){} else{} code, and just request the REMOTE_ADDR:
$ip = $_SERVER["REMOTE_ADDR"];
It's the only reliable source of a user's remote IP address as all the other _SERVER keys can be masked by the client.
If the IP address is still local (and youre SURE that you're dealing with clients not in the networks or on a local VPN) the you may be dealing with either a server caching system (Squid Proxy eg). Have a look at http://www.nineteenlabs.com/2007/08/24/high-anonymous-proxy-squid-25/