Show DevBest [PHP - PDO] VPN/Proxy Restriction

MayoMayn

BestDev
Oct 18, 2016
1,423
683
Since y'all got me in a good mood, I'm going to release this script that I coded.
For more information about how this service works check out the website that checks the IP's:


Okay, so first off we gotta create a function called getIP()
PHP:
public function getIP() 
    {
        //Just get the headers if we can or else use the SERVER global
        if(function_exists('apache_request_headers')) {
            $headers = apache_request_headers();
        } else {
            $headers = $_SERVER;
        }
        //Get the forwarded IP if it exists
        if(array_key_exists('X-Forwarded-For', $headers) && filter_var($headers['X-Forwarded-For'], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
            $ip = $headers['X-Forwarded-For'];
        } elseif(array_key_exists('HTTP_X_FORWARDED_FOR', $headers) && filter_var($headers['HTTP_X_FORWARDED_FOR'], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
            $ip = $headers['HTTP_X_FORWARDED_FOR'];
        } else {
            $ip = filter_var($_SERVER['REMOTE_ADDR'], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4);
        }

        return $ip;
    }

Okay, so in the same class, create a function called curl()
PHP:
public function curl($url, $json=false)
{
        //Check if server has curl library installed
        if(function_exists('curl_init')) {
            // Initiate curl
            $ch = curl_init();
            // Disable SSL verification
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            // Will return the response, if false it prints the response
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            // Set the url
            curl_setopt($ch, CURLOPT_URL, $url);
            // Execute
            $response = curl_exec($ch);
            // Close curl
            curl_close($ch);
        } else {
            // Ordinary get content
            $response = file_get_contents($url);
        }

        if($json == true) {
            //Return as JSON data.
            $response = json_decode($response, true);
        }

        return $response;
    }

So for the second last step, we gotta create a function called validIP() which validates the visitors IP
PHP:
public function validIP()
{
        $db = $this->db;
        $config = $this->config;
        $uip = $this->getIP();
        //Check if session variables are set
        if(isset($_SESSION['ip_banned']) && isset($_SESSION['visitor_ip']) && $_SESSION['visitor_ip'] === $uip) {
            if($_SESSION['ip_banned'] == 0) {
                $ipBanned = 0;
                $status = true;
            } else {
                $ipBanned = 1;
                $status = false;
            }
        } else {
            //Check if Visitor exists inside our Database Table
            $stmt = $db->query("SELECT `banned`,`result` FROM `visitor_ips` WHERE `ip` = :ip LIMIT 1");
            $stmt->bindParam(':ip', $uip, $db->PARAM_STR);
            $stmt->execute();
            if($stmt->rowCount() > 0) {
                $ip = $db->assoc($stmt);
                if($ip['banned'] == '0' && $ip['result'] < '1') {
                    $ipBanned = 0;
                    $status = true;
                } else {
                    $ipBanned = 1;
                    $status = false;
                }
            } else {
                //Get url for IP Validation
                $url = 'https://check.getipintel.net/check.php?ip='.$uip.'&flags=f&format=json&oflags=bc&contact='.$config->hotel('mail');
                //Initiate
                $json = $this->curl($url, true);

                if($json['status'] == "success") {
                    if($json['BadIP'] == "0") {
                        $continue = true;
                        if($config->hotel('c_allow_check') == true) {
                            if(!in_array($json['Country'], $config->hotel('c_allow'))) {
                                $continue = false;
                                $ipBanned = 1;
                            }
                        }
                        if($continue == true) {
                            if($json['result'] >= '1') {
                                $ipBanned = 1;
                            } else {
                                $ipBanned = 0;
                            }
                        }
                    } else {
                        $ipBanned = 1;
                    }
                } else {
                    $ipBanned = 0;
                }
                // If Visitor does not exists in our table insert them into.
                $stmt = $db->query("INSERT INTO `visitor_ips` (`ip`,`banned`,`result`,`agent`) VALUES (:ip,:b,:r,:a)");
                $data = [
                    ':ip' => $uip,
                    ':b' => $ipBanned,
                    ':r' => $json['result'],
                    ':a' => $_SERVER['HTTP_USER_AGENT']
                ];
                if($stmt->execute($data)) {
                    if($ipBanned == 0) {
                        $status = true;
                    } else {
                        $status = false;
                    }
                }
            }
            $_SESSION['visitor_ip'] = $uip;
            $_SESSION['ip_banned'] = $ipBanned;
        }

        return $status;
    }

Run this SQL as a query to create the table needed.
Code:
DROP TABLE IF EXISTS `visitor_ips`;
CREATE TABLE `visitor_ips` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `ip` varchar(45) NOT NULL,
  `banned` enum('0','1') NOT NULL,
  `result` varchar(255) NOT NULL,
  `agent` text NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
For this to work, you gotta recode the MySQL queries so it works for your own service.
By researching, you can create the most amazing stuff.
 
Last edited:

MayoMayn

BestDev
Oct 18, 2016
1,423
683
For further usage, I've updated the validation of the getIP function, since it returned some flaws on mine.
 
Instead of creating a whole other thread, I might aswell just post it here as it serves the same purpose.
Basically I've coded this as a detection package for NodeJS that can be found here:

Currently waiting for to receive the "proxy-detection" package name.
 

Weasel

👄 I'd intercept me
Nov 25, 2011
4,135
2,461
For further usage, I've updated the validation of the getIP function, since it returned some flaws on mine.
 
Instead of creating a whole other thread, I might aswell just post it here as it serves the same purpose.
Basically I've coded this as a detection package for NodeJS that can be found here:

Currently waiting for to receive the "proxy-detection" package name.
I think it's better to create a seperate thread for it, easier to find! You're really getting into Node.
 

7r1n17y

New Member
Jun 11, 2017
13
5
You should not use this because $_SERVER['HTTP_X_FORWARDED_FOR'] or $_SERVER['HTTP_CLIENT_IP'] can be edited by the connecting user witch opens up a security risk. The best way to the IP address is $_SERVER['REMOTE_ADDR']. Anything that is a HTTP var can be edited by the user.
 

7r1n17y

New Member
Jun 11, 2017
13
5
You clearly know jack shit of PHP mate.
Maybe you should try to research the big differences between HTTP_X_FORWARDED_FOR, HTTP_CLIENT_IP and REMOTE_ADDR before you comment more shit.
Actually i am right if you look at this post and look at the best answer it show which vars are a risk . Before hating on my comment check your sources. Let me put it like this. The risk with X-Forwarded-For is that a user could create the header themselves, and thus pass along any IP they wish. Just like my first comment on the other thread security depends on the idiot programming it.
 
Last edited:

MayoMayn

BestDev
Oct 18, 2016
1,423
683
Actually i am right if you look at this post and look at the best answer it show which vars are a risk . Before hating on my comment check your sources. Let me put it like this. The risk with X-Forwarded-For is that a user could create the header themselves, and thus pass along any IP they wish. Just like my first comment on the other thread security depends on the idiot programming it.
You still keep avoiding your own statement. You clearly don't know the differences between the various server variables. If you could read PHP code, you would then realize the IP is being validated. Second of all, if it's not even a valid IP in the end, the getipintel will return it as a failed attempt.

I get it, you think you know everything because you can figure out how to research. Let me tell you something, if you don't even know what the hell you're searching for in the end that is relevant to the topic, then it doesn't even matter.

Do some research and come up with a better solution for receiving the users IP in PHP. That is the only way that validates the IP correctly depending on your own server, and if the visitor is using a proxy or VPN.

Tell me, what is the purpose of HTTP_X_FORWARDED_FOR vs HTTP_CLIENT_IP vs REMOTE_ADDR

This is an old script I created that could easily be improved if I bothered to code PHP again, but I cba.
 
Last edited:

Ari

Member
Sep 29, 2010
320
48
I assume this looks up the IP and checks whether it is a known VPN or datacenter IP?
To get true vpn/proxy protection you should block all datacenter IPs and only allow residential ones.
 

MayoMayn

BestDev
Oct 18, 2016
1,423
683
I assume this looks up the IP and checks whether it is a known VPN or datacenter IP?
To get true vpn/proxy protection you should block all datacenter IPs and only allow residential ones.
Instead of asking such a question, you should visit their website to read the answer.
 

Seriosk

Programmer;
Oct 29, 2016
256
105
It's useful sure, just the fact is also blocks vps servers and tore nodes would be an issue for me. Anyway.. good job.
 

Zombzon

New Member
Jun 18, 2017
6
0
To verify, try it:
$proxy_ports = array(80, 8080, 443); // if necessary add ports
foreach($proxy_ports as $i=>$v) {
if($_SERVER['REMOTE_PORT'] == $v) die('VPNs are not allowed!');
}
$proxy_headers = array(
'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'
);
foreach($proxy_headers as $i=>$v) {
if(isset($_SERVER[$v])) die('VPNs are not allowed!');
}
 

Seriosk

Programmer;
Oct 29, 2016
256
105
To verify, try it:
$proxy_ports = array(80, 8080, 443); // if necessary add ports
foreach($proxy_ports as $i=>$v) {
if($_SERVER['REMOTE_PORT'] == $v) die('VPNs are not allowed!');
}
$proxy_headers = array(
'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'
);
foreach($proxy_headers as $i=>$v) {
if(isset($_SERVER[$v])) die('VPNs are not allowed!');
}
Could of at least used the [] CODE tags, anyway.. this can easily be bypassed.
 

Ecko

23:37 [autobots] -!- eckostylez [[email protected]]
Nov 25, 2012
1,397
961
To verify, try it:
$proxy_ports = array(80, 8080, 443); // if necessary add ports
foreach($proxy_ports as $i=>$v) {
if($_SERVER['REMOTE_PORT'] == $v) die('VPNs are not allowed!');
}
$proxy_headers = array(
'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'
);
foreach($proxy_headers as $i=>$v) {
if(isset($_SERVER[$v])) die('VPNs are not allowed!');
}
This is useless if you are using Nginx or Varnish as a reverse proxy to your web server.
 

Users who are viewing this thread

Top