Search code examples
nginxproxydetection

Unable to detect proxy on new server


I use the following code to detect if users are behind proxy/vpn:

function checkUser()
{
    $proxy = null;
    $check = null;
    $proxy = ($_SERVER['HTTP_ACCEPT_ENCODING'] != 'gzip, deflate') ? true : false;
    if(empty($_SERVER['HTTP_CONNECTION']) || strtolower($_SERVER['HTTP_CONNECTION']) != 'keep-alive' || $_SERVER['HTTP_CACHE_CONTROL'] != 'max-age=0')
    {
        $check = ($proxy === true) ? 'proxy' : 'vpn';
    }
    return $check;
}
$connection = checkUser();
switch($connection)
{
    case 'proxy': $var = 'It seems you are behind Proxy.'; break;
    case 'vpn': $var = 'It seems you are using VPN.'; break;
    default: $var = 'No Proxy or VPN detected.'; break;
}
echo $var;

However it does work just fine on an older server I have, but on the new one it just doesn't. The new server is using Reverse Proxy Server (nginx). Can someone tell me if it has something to do with nginx and what I should adjust at the config. Thanks!

--- EDIT: ---

#user  nginx;
worker_processes  4;
worker_rlimit_nofile 950000;


#error_log  /var/log/nginx/error.log;
#error_log  /var/log/nginx/error.log  notice;
#error_log  /var/log/nginx/error.log  info;

#pid        /var/run/nginx.pid;


events {
    worker_connections  45000;
}


http {
    include       mime.types;
    default_type  application/octet-stream;

    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';

    #access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  5;
    #tcp_nodelay        on;

    #gzip  on;
    #gzip_disable "MSIE [1-6]\.(?!.*SV1)";

    server_tokens off;

    include /etc/nginx/conf.d/*.conf;

        fastcgi_buffers 8 16k;
        fastcgi_buffer_size 32k;
        fastcgi_connect_timeout 300;
        fastcgi_send_timeout 300;
        fastcgi_read_timeout 300;
}

Solution

  • Your code seems to be based on the assumption that a proxy would disable the use of gzip/deflate and/or keep-alive sessions. This is not an accurate assumption. It is easier to implement a proxy if these features are turned off, but per the spec there is nothing that precludes a proxy working correctly with these features on.

    So yes, nginx is probably just a better proxy and so the assumptions made by the author of that code above are now wrong.

    The right way to check for an HTTP proxy is to look for the presence of an X-Forwarded-For header. Something like this would suffice:

    function isProxied() {
        $headers = array_change_key_case(apache_request_headers());
        return isset($headers["x-forwarded-for"]);
    }
    

    Technically, a proxy can be implemented without advertising it's presense (without adding an X-Forwarded-For header) - and some have an option to do this, in which case you're not really going to be able to detect this. But most propxies will cooperate with you.

    Note that if you are using a proxy in your own server stack (i.e. if you are running Varnish, Nginx or something else in front of Apache) then that could also adding an X-Forwarded-For header, so everything would appear to be proxied (based on this, it looks like nginx uses "X-Real-IP" by default, so you likely don't need to worry about this). If this is the case, either turn off the that option in Varnish/Nginx/whatever, or parse the X-Forwarded-For header to see if there are two IPs there instead of one.

    Regarding VPN connections, I do not think you are going to find a reliable way to detect if the user is on VPN just from an incoming HTTP connection. Although you might consider checking his origin IP to see if he is coming from a known TOR address or something of the sort. Depending on how much you care about that.