I'm trying to figure out how I could detect whether people logging into my site are behind a proxy or not. I've read that you can detect a person's real IP address through embeddable objects (Flash and Java). However, I haven't been able to actually find any examples or source for this.
I'm using PHP and I've read that looking for $_SERVER['HTTP_X_FORWARDED_FOR'], $_SERVER['HTTP_CLIENT_IP'], etc. would detect most proxies but so far I haven't been able to by testing with TOR (maybe TOR doesn't flag those, but I've read that anonymous proxies still show HTTP_X_FORWARDED). I'd like to try doing it with a java servlet, if possible. Could anyone point me in the right direction (preferably with examples?) I saw some code on ha.ckers.org but they only showed the client side and not the server side.
TOR does not supply any server headers such as X_FORWARDED_FOR, so your best bet is to use a list of all known exit nodes. A list can be found at https://torstat.xenobite.eu/.
For other proxies, you can look at server headers. Possible server headers of interest include:
HTTP_VIA
HTTP_X_FORWARDED_FOR
HTTP_FORWARDED_FOR
HTTP_X_FORWARDED
HTTP_FORWARDED
HTTP_CLIENT_IP
HTTP_FORWARDED_FOR_IP
VIA
X_FORWARDED_FOR
FORWARDED_FOR
X_FORWARDED FORWARDED
CLIENT_IP
FORWARDED_FOR_IP
HTTP_PROXY_CONNECTION
In PHP, you can get the value of these fields in the $_SERVER[] superglobal.
If your want to check weather the user is using proxy or not you can go with the port scan and checking the headers when request is made. These method will reveal public IP if the proxy is non-transparent (By the way there are two types of IP address public and private IP address). But this will not work if it is transparent proxy.
function detectProxy() {
$sockport = false;
$proxyports=array(80,8080,6588,8000,3128,3127,3124,1080,553,554);
for ($i = 0; $i <= count($proxyports); $i++) {
if(#fsockopen($ipaddress,$proxyports[$i],$errstr,$errno,0.5)){
$sockport=true;
}
}
if(
isset($_SERVER['HTTP_VIA'])
|| isset($_SERVER['HTTP_X_FORWARDED_FOR'])
|| isset($_SERVER['HTTP_FORWARDED_FOR'])
|| isset($_SERVER['HTTP_X_FORWARDED'])
|| isset($_SERVER['HTTP_FORWARDED'])
|| isset($_SERVER['HTTP_CLIENT_IP'])
|| isset($_SERVER['HTTP_FORWARDED_FOR_IP'])
|| isset($_SERVER['VIA'])
|| isset($_SERVER['X_FORWARDED_FOR'])
|| isset($_SERVER['FORWARDED_FOR'])
|| isset($_SERVER['X_FORWARDED'])
|| isset($_SERVER['FORWARDED'])
|| isset($_SERVER['CLIENT_IP'])
|| isset($_SERVER['FORWARDED_FOR_IP'])
|| isset($_SERVER['HTTP_PROXY_CONNECTION'])
|| $sockport === true
) {
echo 'User is using proxy';
}
else{
echo ''user is not using proxy';
}
}
Second method is by using DNS server by allocating sub domain to each user.
You can also check this site proxy checker which will show public and private IP address even when you are using proxy.
Neither Java Applets or Flash is supposed to leak the client IP. I know that older versions of Flash had a security flaw that made it possible. Most probably that is patched by now.
I've never used TOR but from what I read it seems to be implemented as a kind of VPN and thus the browser will not be aware of it at all.
Why do you need to know if the user is behind a proxy?
If it's an option you can try using https. The user IP then should be visible to you. However don't know about office users behind SSL proxies.
By looking for the following header fields you should some proxys.
VIA
FORWARDED
USERAGENT_VIA
X_FORWARDED_FOR
PROXY_CONNECTION
XPROXY_CONNECTION
HTTP_PC_REMOTE_ADDR
HTTP_CLIENT_IP
As for blocking TOR you are best of blocking the TOR exit nodes with iptables.
And if you really must be sure you could try some "semi-malicious" things like embedding some flash or java in your page which sends you back the real client ip. But that has only limited scope as you might just get the local ip if he is in e.g. a LAN you get something like 192.168.1.x
Once you have the client IP address, the simplest is to pass it to a service that maintains an up-to-date list of TOR exit nodes. You can for instance use Ipregistry (disclaimer: I run the service):
https://api.ipregistry.co/89.187.143.81?key=tryout
where 89.187.143.81 must be replaced by your client IP and tryout by your API key.
In the output, look at the field security -> is_tor_exit. If the boolean is true, then your client is using Tor.
Related
I would like to make a PHP website, where employees can log in/out themselves and these logs will count as a time when they started and ended their working day. I would like to allow them to do that only on their work computer and not for example on their phone while they are still on the way, but they want to avoid "being late".
So I'm struggling with a few ideas, but any of them seems to be the right solution.
Allow using the website only for specific IP addresses. But then I realized that in our place IP address is dynamic and changing it for static costs too much in our area.
Check user location. But then I saw that when I'm checking my public IP address, the location is completely wrong! Our building isn't even close to the loaded area.
Using a COOKIE/token on a work computer. But it's very easy to set the same cookie on your own device and I'm not the only IT employee here.
Checking MAC address. As I read here it's possible only in specific cases.
Block access for mobiles. But detecting a mobile is based on browser and if the user click "Request Desktop Site" scripts will say that's a computer.
Is there another method, which I can use to achieve my goal? Am I missing something?
May I bind my app for example with some other technologies that will allow me to do that? Or maybe I should try a combination of all of them?
I couldn't find any script, which would take care of that. In the worst case it doesn't have to be "perfectly secure", but I would like to be it at least hard, annoying, or time-consuming to try to "cheat" in this system.
I would run your app in the office LAN. Nobody will be able to access it from outside except if they can do remote desktop to the office computer or if they have VPN. But if you are in the IT team you may could fix IP ranges for the office computers so that you could exclude the VPN.
In terms of security, in any case it may be better having it running in your LAN. I'm sure you've got a server somewhere and if it's not the case then you could use a NAS (Synology offers NGINX, Apache, PHP and much more) or a little Rasperry Pie or something similar.
If you haven't got a fixed IP, you could also use DynDNS and have it mapped to a sub-domain such as company-name.dyndns.org and then on your PHP app you could have a cron job that gets the IP address from the domain name and updates it every minutes (I'm sure it's quickly run). It could then store it inside a config file, this way:
<?php
define('ALLOWED_IP_FILE', 'allowed-ips.inc.php');
$ALLOWED_DOMAINS = [
'your-company.dyndns.org',
'you-at-home.dyndns.org',
];
$allowed_ips = [];
foreach ($ALLOWED_DOMAINS as $allowed_domain) {
$ip = gethostbyname($allowed_domain);
if ($ip !== $allowed_domain) {
// Store with the IP in the key and value for ease when checking the IP validity.
$allowed_ips[$ip] = $ip;
} else {
fprintf(STDERR, "ERROR: Could not find the IP of $allowed_domain!\n");
}
}
$allowed_ips_export = var_export($allowed_ips, true);
$config_file_content = <<<END_OF_CONFIG
<?php
// Don't edit! This config file is generated by cron-ip-address.php.
\$ALLOWED_IPS = $allowed_ips_export;
END_OF_CONFIG;
if (file_put_contents(ALLOWED_IP_FILE, $config_file_content) === false) {
fprintf(STDERR, 'ERROR: Could not write config file ' . ALLOWED_IP_FILE . "\n");
}
This generates a config file to include in your app. Example of content generated if you run the script I wrote above:
<?php
// Don't edit! This config file is generated by cron-ip-address.php.
$ALLOWED_IPS = array (
'142.250.203.99' => '142.250.203.99',
'23.201.250.169' => '23.201.250.169',
);
Now, in your app, just include it and test the presence of the IP in the $ALLOWED_IPS array:
<?php
include ALLOWED_IP_FILE; // If this is declared in a common config file.
// include 'allowed-ips.inc.php'; // If you haven't got a common config file.
if (!isset($ALLOWED_IPS[$_SERVER['REMOTE_ADDR']])) {
http_response_code(403);
die('Sorry, you cannot access it from here.');
}
Ideally, if what you actually want to track is when employees are in the workplace and logged on / for how long, it would be probably better to just track local machine-logins via a domain controller - a method reachable from the internet is suboptimal exactly for the reasons you mentioned.
If you have an intranet which users cannot tunnel into but can access from their work machines, I'd say hosting your login-page only inside that intranet is the easiest way to achieve what you want with the methods you suggest.
Alternatively, if employee work-machines use windows under a domain controller - you can restrict access to Windows certificate-storage, then install/push a certificate and require that to be present via your server-configuration. In that case, it doesn't matter if the website is accessible from the internet. I'm sure there are similar solutions if work-machines are not on Windows.
This admittely old question gives some pointers in the right direction on how to require client certificates from a Webserver (IIS in that case).
What is the most accurate way to get user's IP address in 2017 via PHP?
I've read a lot of SO questions and answers about it, but most of answers are old and commented by users that these ways are unsafe.
For example, take a look at this question (2011): How to get the client IP address in PHP?
Tim Kennedy's answer contains a recommendation to use something like:
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'];
}
But as I've read a lot, I have seen that to use X_FORWARDED_FOR is unsafe, as the comment below highlights:
Do NOT use the above code unless you know EXACTLY what it does! I've
seen MASSIVE security holes due to this. The client can set the
X-Forwarded-For or the Client-IP header to any arbitrary value it
wants. Unless you have a trusted reverse proxy, you shouldn't use any
of those values.
As I didn't know EXACTLY what it does, I don't want to take the risk. He said it is unsafe, but did not provide a safe method to get user's IP address.
I've tried the simple $_SERVER['REMOTE_ADDR'];, but this returns the wrong IP. I've tested this and my real IP follows this pattern: 78.57.xxx.xxx, but I get an IP address like: 81.7.xxx.xxx
So do you have any ideas?
Short answer:
$ip = $_SERVER['REMOTE_ADDR'];
As of 2021 (and still) $_SERVER['REMOTE_ADDR']; is the only reliable way to get users ip address, but it can show erroneous results if behind a proxy server.
All other solutions imply security risks or can be easily faked.
From a security POV, nothing but $_SERVER['REMOTE_ADDR'] is reliable - that's just the simple truth, unfortunately.
All the variables prefixed with HTTP_ are in fact HTTP headers sent by the client, and there there's no other way to transfer that information while requests pass through different servers.
But that of course automatically means that clients can spoof those headers.
You can never, ever trust the client.
Unless it is you ... If you control the proxy or load-balancer, it is possible to configure it so that it drops such headers from the original request.
Then, and only then, you could trust an e.g. X-Client-IP header, but really, there's no need to at that point ... your webserver can also be configured to replace REMOTE_ADDR with that value and the entire process becomes transparent to you.
This will always be the case, no matter which year we are in ... for anything related to security - only trust REMOTE_ADDR.
Best case scenario is to read the HTTP_ data for statistical purposes only, and even then - make sure that the input is at least a valid IP address.
You have to collaborate with your sysops team (or if you're wearing that hat too, you will need to do some research). The header check is used when your network infrastructure is configured in certain ways where the remote requester is one of your network appliances instead of the end
user.
This sort of thing happens when your web server(s) sit behind a load balancer or firewall or other appliance that needs to interrogate the payload to properly handle it. An example is when a load balancer terminated ssl and forwards the request on to the web server without ssl. When this occurs the remote address becomes the load balancer. It also happens with firewall appliances that do the same thing.
Most instances the device will offer configuration to set a header value in the request with the original remote ip address. The header is usually what you'd expect but it can in some cases be different or even configurable.
What's more, depending on your web server configuration (apache, nginx or other) may not support or be currently configured to support certain custom headers such as the common ip header.
The point is us you will need to investigate your network configuration to ensure that the original requester's ip makes it all the way through to your application code and in what form.
If you'd like to use a pre-built library, you can use Whip.
Using pre-made libraries are usually better because most of them will have been checked thoroughly by an active community. Some of them, especially the ones that have been around for a long time, have more features built-in.
But if you want to code it yourself to learn the concept, then it's ok I guess. I recommend packaging it as a stand alone library and releasing it as open-source :)
EDIT: I do not recommend using the remote IP in security mechanisms as they are not always reliable.
First, it is impossible to reliably determine someone's source IP address if they are intent on being hidden. Even something which today seems foolproof, will soon have a loophole (if it doesn't already). As such, any answer below should be considered UNTRUSTED, which means that if you put all of your eggs in this basket, be prepared for someone to take advantage of it or circumvent it somehow.
I won't get in to all the ways someone can circumvent IP tracking, because
it is constantly evolving. What I will say is that it can be a useful tool for logging as long as you know that IP addresses can easily change or otherwise be masked.
Now, one big point to make is that there is a difference between a public IP address and a private IP address. In IPV4, routers are generally assigned one public IP address, which is all that a server-side language can actually grab, because it doesn't see your client-side IP address. To a server, your computer doesn't exist as a web-space. Instead, your router is all that matters. In turn, your router is the only thing that cares about your computer, and it assigns a private IP address (to which your 172...* address belongs) to make this work. This is good for you, because you can't directly access a computer behind a router.
If you want to access a private IP address, you need to use JavaScript (client-side language). You can then store the data asynchronously via AJAX. As far as I know, this is only currently possible using WebRTC-enabled Chrome and Firefox. See here for a demo.
I tested this and it returns private IP addresses. Typically I think this is used by advertisers to help track individual users in a network, in conjunction with the public IP address. I am certain that it will quickly become useless as people come up with workarounds or as public outcry forces them to offer the ability to disable the WebRTC API. However, for the time being it works for anyone who has JavaScript enabled on Chrome and Firefox.
More Reading:
What is a Private Network?
STUN IP Address requests for WebRTC
Quick Link: IP address checker
Get Client IP Address:
<?php
echo $ip = $_SERVER['REMOTE_ADDR'];
?>
Note::
This would work only on live site, because on your local host your ip would be one (1) of the internal ip addresses, like 127.0.0.1
So, its Return ::1
Example : https://www.virendrachandak.com/demos/getting-real-client-ip-address-in-php.php
Its Show Your Local Ip:
Like ... 78.57.xxx.xxx
Example:
<?php
$myIp= getHostByName(php_uname('n'));
echo $myIp;
?>
As the real method is to check user IP is $ip = $_SERVER['REMOTE_ADDR'];
If the user is using VPN or any proxy then it will not detect the original IP.
How about this one -
public function getClientIP()
{
$remoteKeys = [
'HTTP_X_FORWARDED_FOR',
'HTTP_CLIENT_IP',
'HTTP_X_FORWARDED',
'HTTP_FORWARDED_FOR',
'HTTP_FORWARDED',
'REMOTE_ADDR',
'HTTP_X_CLUSTER_CLIENT_IP',
];
foreach ($remoteKeys as $key) {
if ($address = getenv($key)) {
foreach (explode(',', $address) as $ip) {
if ($this->isValidIp($ip)) {
return $ip;
}
}
}
}
return '127.0.0.0';
}
private function isValidIp($ip)
{
if (!filter_var($ip, FILTER_VALIDATE_IP,
FILTER_FLAG_IPV4 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)
&& !filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 | FILTER_FLAG_NO_PRIV_RANGE)
) {
return false;
}
return true;
}
I use this code, and it works for me. Take a look to it.
<?php
// Gets client's IP.
$ip = getenv("HTTP_CLIENT_IP")?:
getenv("HTTP_X_FORWARDED_FOR")?:
getenv("HTTP_X_FORWARDED")?:
getenv("HTTP_FORWARDED_FOR")?:
getenv("HTTP_FORWARDED")?:
getenv("REMOTE_ADDR");
echo $ip;
?>
Here, a working example. Hope it helps!
Because of different network setups (proxy servers, private networks, etc.) and how administrators configure their networks, it is difficult to obtain the client IP address. Standards are being addressed related to this issue.
The following function worked in 4 different tests (Home Network, VPN, Remote connection, public internet). The code can be used as base code for your project. Modify as needed.
The function does validate the IP address, but does not validate IP ranges. This would be an additional test after you obtain the client IP.
$_SERVER["REMOTE_ADDR"] does not always return the true client IP address.
Because some of the parameters can be set by end users, security can be an issue.
Set Client IP address
$clientIpAddress = $du->setClientIpAddress($_SERVER);
public function setClientIpAddress($serverVars) {
# Initialization
$searchList = "HTTP_CLIENT_IP,HTTP_X_FORWARDED_FOR,HTTP_X_FORWARDED,HTTP_X_CLUSTER_CLIENT_IP,HTTP_FORWARDED_FOR,HTTP_FORWARDED,REMOTE_ADDR";
$clientIpAddress = "";
# Loop through parameters
$mylist = explode(',', $searchList);
foreach ($mylist as $myItem) {
# Is our list set?
if (isset($serverVars[trim($myItem)])) {
# Loop through IP addresses
$myIpList = explode(',', $serverVars[trim($myItem)]);
foreach ($myIpList as $myIp) {
if (filter_var(trim($myIp), FILTER_VALIDATE_IP)) {
# Set client IP address
$clientIpAddress = trim($myIp);
# Exit loop
break;
}
}
}
# Did we find any IP addresses?
if (trim($clientIpAddress) != "") {
# Exit loop
break;
}
}
# Default (if needed)
if (trim($clientIpAddress) == "") {
# IP address was not found, use "Unknown"
$clientIpAddress = "Unknown";
}
# Exit
return $clientIpAddress;
}
I run security checks on a number of AJAX calls to see if the same IP requested that I have on record.
I used the following set of class functions to establish the IP (which can come via load balancers, hence the lengthly methodology.
private function IPMask_Match ($network, $ip) {
$ip_arr = explode('/', $network);
if (count($ip_arr) < 2) {
$ip_arr = array($ip_arr[0], null);
}
$network_long = ip2long($ip_arr[0]);
$x = ip2long($ip_arr[1]);
$mask = long2ip($x) == $ip_arr[1] ? $x : 0xffffffff << (32 - $ip_arr[1]);
$ip_long = ip2long($ip);
return ($ip_long & $mask) == ($network_long & $mask);
}
private function IPCheck_RFC1918 ($IP) {
$PrivateIP = false;
if (!$PrivateIP) {
$PrivateIP = $this->IPMask_Match('127.0.0.0/8', $IP);
}
if (!$PrivateIP) {
$PrivateIP = $this->IPMask_Match('10.0.0.0/8', $IP);
}
if (!$PrivateIP) {
$PrivateIP = $this->IPMask_Match('172.16.0.0/12', $IP);
}
if (!$PrivateIP) {
$PrivateIP = $this->IPMask_Match('192.168.0.0/16', $IP);
}
return $PrivateIP;
}
public function getIP () {
$UsesProxy = (!empty($_SERVER['HTTP_X_FORWARDED_FOR']) || !empty($_SERVER['HTTP_CLIENT_IP'])) ? true : false;
if ($UsesProxy && !empty($_SERVER['HTTP_CLIENT_IP'])) {
$UserIP = $_SERVER['HTTP_CLIENT_IP'];
}
elseif ($UsesProxy && !empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$UserIP = $_SERVER['HTTP_X_FORWARDED_FOR'];
if (strstr($UserIP, ',')) {
$UserIPArray = explode(',', $UserIP);
foreach ($UserIPArray as $IPtoCheck) {
if (!$this->IPCheck_RFC1918($IPtoCheck)) {
$UserIP = $IPtoCheck;
break;
}
}
if ($UserIP == $_SERVER['HTTP_X_FORWARDED_FOR']) {
$UserIP = $_SERVER['REMOTE_ADDR'];
}
}
}
else{
$UserIP = $_SERVER['REMOTE_ADDR'];
}
return $UserIP;
}
The Problem is I've been getting problems with users operating via a proxy. Can anyone indicate why that might be? I've used basic free proxy's online to try and emulate, but it doesn't look to be getting variable IPs or anything - so I'm not sure why this would be saying the two IPs don't match.
I am going to explain what a proxy is first so we are both on the same page.
What Is A Proxy
A proxy is usually a single computer that accesses the internet ON BEHALF OF the user and then the proxy sends the results back to the user. The problem appears when there could be hundreds or even thousands of other people also using that one computer - and they all have the SAME IP address but normally the headers indicate that the users are via a proxy.
Your script i am assuming (without properly looking) is getting the IP's and headers mixed up.
Different Solution
There is a better way. Use sessions and save a key in the session ensuring they have previously been to the main site first BEFORE accessing the ajax page. Example:
index.php
session_start();
$_SESSION['ajax_ok'] = true;
ajax/username_check.php
session_start();
if (empty($_SESSION['ajax_ok'])) {
die("You can not access this page...");
}
That will enforce that they must visit your main site first and the client must also support sessions which most browsers will which is a plus to help prevent bots etc abusing your ajax scripts.
More reliable and easier solution than using that mangle of code you got above ><
What if you can't use sessions?
If you can't use sessions on the specific comp you're on, you could setup another computer, rewrite the session handler (using the callbacks that php provides) or instead of using the file system use something else like the database for sessions instead? There must be something your website uses that the sessions could also use. Such as if you have a load balancer file based sessions generally wont work anyway so it's generally a good idea to change the sessions to use something else like i mentioned above.
The problem unfortunately almost certainly isn't a proxy - it's almost certainly a stationary public IP router, routing traffic through a subnet.
And subnets can be HUGE (say, at universities).
And even if it was by some fluke a genuine proxy (they are rare these days - 10 year old tech), even if the proxy volunteers to forward, it won't happen to mean anything because it's almost certainly a subnet ip like 192.168.x.x anyway.. This is basically the public IP address (aka switchboard) internal extension.
You could cross your fingers and try php ipv6 Working with IPv6 Addresses in PHP or even be even more clever and try mac address How can I get the MAC and the IP address of a connected client in PHP? but both are doomed to failure. My gut instinct is to try to cheat: I would gamble that the best way is basically using a network share for the session store and allowing the load balanced PHP servers to all access it and do everything via the same dns prefix. Or perhaps set up a 3rd party dns for doing the sessional gathering.
The answer is that unless you track with "cookies" like your an ad agency you can't do it.
A friend identified this, basically some proxy's can come back with X_FORWARDED_FOR as a comma separated value OR as comma separated and spaced.
To fix:-
after:
foreach ($UserIPArray as $IPtoCheck) {
add this line:
$IPtoCheck = trim($IPtoCheck);
Sorted.
The Problem is I've been getting problems with users operating via a
proxy. Can anyone indicate why that might be? I've used basic free
proxy's online to try and emulate, but it doesn't look to be getting
variable IPs or anything - so I'm not sure why this would be saying
the two IPs don't match.
Your parsing code explodes HTTP_X_FORWARDED_FOR on comma, but separator may be "comma space". If that happens, the RFC 1918 check will fail. While some proxies do not add space, the standard is to use it:
http://en.wikipedia.org/wiki/X-Forwarded-For
The general format of the field is:
X-Forwarded-For: client, proxy1, proxy2
where the value is a comma+space separated list of IP addresses, the
left-most being the original client, and each successive proxy that
passed the request adding the IP address where it received the request
from. In this example, the request passed proxy1, proxy2 and proxy3
(proxy3 appears as remote address of the request).
So you ought to change the explode separator to ", ", or better, use preg_split with ",\s*" as a separator and cover both cases.
Then, your problem is to authenticate the page doing the call in AJAX to the AJAX call itself.
If you don't want to use cookie-based sessions, which is the best way, you can try and do this with a nonce. That is, when you generate the page, you issue a unique ID and inject it into the HTML code, where the AJAX code will recover it and pass back to the AJAX servlet. The latter will be able to add it in Access-Control-Request, as detailed here, or just add more data to the request.
I'd like to discuss whether your solution does anything on behalf of security.
$_SERVER['REMOTE_ADDR'] cannot be forged. It is set by the webserver because of the accessing IP address used. Any response goes to this address.
$_SERVER['HTTP_FORWARDED_FOR'] and $_SERVER['HTTP_CLIENT_IP'] can easily be forged, because they are HTTP headers sent to the webserver - neither will you know you are talking to a proxy if it is configured to omit these headers, nor will you know you are NOT talking to a proxy if a client decides to insert these headers.
Filtering based on the IP address FORGED will not really help you, but this highly depends on the stuff you want to achieve - which remains unknown until you go into more detail there.
If you look around, you will stumble upon the Suhosin patch and extension for PHP, and it's feature to encrypt the session and cookie content. The encryption key is built by using some static key, but adding stuff like the HTTP User Agent or parts of the requesting IP address - note: The IP used to actually make the request, i.e. the proxy if one is used, because this is the only reliable info.
One can argue that using the full IP address is not a very good idea unless you know your users do not use proxy clusters with changing IP addresses for multiple requests, so only a part of the IP would usually be used, or none at all.
The HTTP User Agent though is a nice source of unique information. Yes, it can be forged, but that does not matter at all, because if you only want to allow requests from the same source, it is valid to assume that the user agent string does not change over time, but will be different for a bunch of other users. Hence there are statistics that show you can generate a nearly unique fingerprint of a browser if you just look at all the HTTP headers sent, because every user installs different extensions that change something, like accept-content headers.
I cannot provide working code, nor can I tell from your question whether any of this answer applies, but I'd suggest not using the IP info, especially if it can be forged. This is even more valid if you think about IPv6, where every client has multiple active addresses even on the same interface, and they are all randomly generated and highly unlikely to ever occur again later in time. (Of course this does not apply if you are never gonna host on IPv6, but at some point you'll be out of users then.)
Is there anyway in PHP to use uniquely identify a user's router? I'd like t know what users are on the same router.
The general answer is going to basically be no - detecting network topology is a non-trivial operation (and certainly detecting the path packets took to you can be well-nigh impossible from an endpoint). However, it sounds like you have some kind of specific topology which perhaps if you tell us more about we might be able to help you with.
Presuming the following things:
You have two ingress routers
Your web server only has one ethernet interface
You're trying to determine which router the traffic came through
You could VLAN tag all incoming traffic at each ingress interface (and put all your hosts on untagged switch interfaces), and give yourself an interface alias on your web server for each VLAN, and thus by knowing which virtual interface you came in on, you'll know what ingress router the traffic came from.
You can retrieve the users IP address using $_SERVER['REMOTE_ADDR'] and then use a traceroute utility to get the hops and check for the routers that you wish to find, if you know the IPs of both of them.
Assuming that the router is not address-translating for them, otherwise this will not work, as it relies on being able to get back through the router to the user. If either router can return to the user, then it will not work at all. Good for dial-in users though.
<?php
$ip = $_SERVER['REMOTE_ADDR'];
$router1IP = "123.123.123.123";
$output = array();
exec('traceroute -n ' . $ip, $output, $result);
if ($result == 0) {
$outputText = implode("\n", $output);
if (preg_match("/" . preg_quote($router1IP) . "/", $output)) {
echo "Router 1";
} else {
echo "Router 2";
}
}
?>
The best you can do is identify a users IP address using the $_SERVER['REMOTE_ADDR']. If ip address corresponds to router, you're in luck.
I still confused on this subject and ask for any help and reference on how to check a visitor IP address via PHP.
I'm know it seems lazy to ask something before attempting to code something to show, but right now, I am also googling to find it. Hopefully someone can give general broad answer or some link to read?
BTW, what is to be considered when we have to code some feature like this?
PS: Thank you very much everybody. It's been enlightening arguments. Frankly, I choose the answer more as respect rather than the truth in it. Because until now I still don't know the right one. Maybe I need more years of learning before I get a firm understanding of the topic itself.
See $_SERVER, specifically:
$_SERVER['REMOTE_ADDR'];
OK, justjoe, I see you got confused with this arguement and there is my big part in it.
Some more explanations for you.
The answer depends on the task. You have 2 options:
If you need only one IP address, you can use only REMOTE_ADDR and nothing else. Take a look at the web-server's access log: there is only one IP address and it's REMOTE_ADDR one. At least it guaranteed you a valid IP address. In many cases, like a traffic counter, it's the only thing you can rely on. Thes is general answer to the "How to get an IP address" question.
If you want to record an address that can be more precise probably - so, no one forbids you from recording many addresses, not one. But of course, you have to record these HTTP headers along with REMOTE_ADDR, not instead of it. There is some use for such a throng of addresses. But you can't rely on it too much. But you can dig some information from it, if you care.
The only case for the FORWARDED_FOR header is a misconfigured webserver, who place the real IP address into this variable. In this case it can be used as an IP address. But of course it must be done manually, in the every particular case, not as the general recommendation. But anyway I'd quit such a webserver as there can't only be one misconfiguration in it.
To get the user IP address you should use this,
$ip = $_SERVER['REMOTE_ADDR']
General broad answer: everything PHP knows about client is stored in the $_SERVER variable.
So, do this code everytime you want particular info to see if you can find something relevant:
echo "<pre>";
print_r($_SERVER);
echo "</pre>";
//or just
phpinfo(32);
$_SERVER['REMOTE_ADDR'] is the only IP address you can get, though it can be not a "client address".
If your client is surfing through a proxy server, then $_SERVER['REMOTE_ADDR'] just returns the IP address of the proxy server — not of the client’s machine. That’s not very reliable. This might be a better solution:
function get_ip_address() {
foreach (array('HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED', 'REMOTE_ADDR') as $key) {
if (array_key_exists($key, $_SERVER)) {
foreach (explode(',', $_SERVER[$key]) as $ip) {
$ip = trim($ip); // just to be safe
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_IPV6 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) !== false) {
self::$ip = $ip;
return $ip;
}
}
}
}
}
This has already been discussed on Stack Overflow before. Please refer to “What is the most accurate way to retrieve a user’s correct IP address in PHP?”. The above code is an optimized version of the accepted answer to that question.
However, do note that getting IP addresses is never fully reliable: php / ajax REMOTE_ADDR set to IP of bogus network adapter
The following would serve the purpose.
$ip = $_SERVER['REMOTE_ADDR'];
echo "IP address is : " :.$ip;
I suggest you use a third-party IP address to a geo converter to calculate the location. Since you wouldn't have to bare the database space.. Accuracy and the queries.
All you will need to do is something like
http://third-party-url.com?ip=IP_ADDRESS
and it gives back XML or an array of data.
You can use that to do whatever you want later on.
Here are two websites which are popular.
* My IP Address Lookup and GeoTargeting
* SimpleGeo
There are many such sites.. Maybe others can add them here.
Just use this at the top of your code:
if (function_exists('apache_request_headers'))
{
$headers = apache_request_headers();
if (array_key_exists('X-Forwarded-For', $headers))
{
$ips = explode(',',$headers['X-Forwarded-For'],2);
$_SERVER["REMOTE_ADDR"]= trim($ips[0]);
}
}
It will make sure that $_SERVER["REMOTE_ADDR"] always keep the proper IP address on load balancers applications or not.