Posted in ColdFusion | Posted on 04-21-2009 | 6,527 views
This week I had a nice (email) conversation with Dave Dugdale. His question was:
I would like to detect if someone is using a proxy server when visiting my site. I found a script in PHP but I couldn't find one written in ColdFusion on Google or your site. Have you ever done one of these?
I certainly had not heard of such a beast, but I asked to see his PHP code. I mean, let's be real, anything written in PHP should be easier in ColdFusion, right?
Dave sent along the PHP code. I'm not sure if this is "good" code or not, but here it is:
2if (
3 $_SERVER['HTTP_X_FORWARDED_FOR'] ||
4 $_SERVER['HTTP_X_FORWARDED'] ||
5 $_SERVER['HTTP_FORWARDED_FOR'] ||
6 $_SERVER['HTTP_CLIENT_IP'] ||
7 $_SERVER['HTTP_VIA'] ||
8 in_array($_SERVER['REMOTE_PORT'],
9 array(8080,80,6588,8000,3128,553,554)) ||
10 @fsockopen($_SERVER['REMOTE_ADDR'],
11 80, $errno, $errstr, 30)
12)
13
14{
15exit('Proxy detected');
16}
17else
18// print the IP address on screen
19//echo ( getenv('REMOTE_ADDR') . ' Welcome 1' );
20//echo ( $_SERVER['REMOTE_ADDR'] . ' Welcome 2' );
21//echo ( @$REMOTE_ADDR . ' Welcome 3' );
22//echo ( getenv('REMOTE_ADDR') . ' Welcome 4' );
23echo ( ' Welcome 5' );
24
25
26// start code
27
28// if getenv results in something, proxy detected
29
30?>
I looked this over. The first thing I told him was that $_SERVER was most likely just a pointer to ColdFusion's CGI scope. Any place he saw that he could just switch it with CGI. For example:
You could then simply add the 4 other CGI variables to the CFIF.
The inArray looks to be a simple "Does this value exist in the array". For that I suggested just using listFindNoCase.
All together, I wrote this up as:
2or cgi.http_x_forwarded neq ""
3or cgi.http_forwarded_for neq ""
4or cgi.http_client_ip neq ""
5or cgi.http_via neq ""
6or listFind("8080,80,6588,8000,3128,553,554", cgi.remote_port)>
7Proxy!
8</cfif>
This seems to work well. But the last clause makes no sense to me or Dave:
2 80, $errno, $errstr, 30)
I'd guess fsockopen is analogous to CFHTTP, but as to what it is checking here, I have no idea. Anyone want to help complete the puzzle?


He could probably do this in his check...
<cfscript>
connection = createObject("java", "java.net.Socket");
connection.init(cgi.remote_addr, 80);
connected = connection.isConnected();
</cfscript>
This probably does something similar to the PHP function. If not, one of the methods in the Socket Class could!
php docs says fsockopen is opening a socket, so for some reason he reaches out to touch the proxy. I'm not sure it makes any sense to do that, but I'm also not sure of the need for any of the other checks if you are simply trying to ID a Proxy use.
I think this should work:
<cfif cgi.HTTP_X_FORWARDED_FOR neq "">
proxy
</cfif>
Also, in your version, there should be one HTTP_X_FORWARDED_FOR instead of two HTTP_X_FORWARDED.
in my opinion this is wrong. he needs to check on the port the connection is comming from (8080, etc.) and not only port 80.
the idea is that if the user uses a proxyserver i should be able to connect back to it too.
what happens if i have a webserver open on my router on port 80 (which is default if i don't use a proxy)? that will be detected as a connection and every connection would mean proxy in this script. bad idea.
I've played around with the code above on this page,
I created this page test http://www.pickrent.com/misc/proxy.cfm I can't seem to get it to work.
Here is the code that is on the link above (from Shag):
<cfif cgi.HTTP_X_FORWARDED_FOR neq "">
<h4>You ARE coming from a proxy.</h4>
<CFELSE>
<h4>You are NOT coming from a proxy.</h4>
</cfif>
The code above always indicates that I am NOT coming from a proxy whether I am or not.
I also tried Ray's code above but it doesn't matter if I am coming from a proxy or not, the code always say that I AM coming from a proxy.
I liked your idea of running the cfdump behind the proxy, so I added that to the code on the test page www.pickrent.com/misc/proxy.cfm" target="_blank">http://www.pickrent.com/misc/proxy.cfm.
Here are my results that are different:
Normal then proxy:
HTTP_ACCEPT_ENCODING gzip,deflate
HTTP_ACCEPT_ENCODING [empty string]
Normal then proxy:
HTTP_ACCEPT_LANGUAGE en-us,en;q=0.5
HTTP_ACCEPT_LANGUAGE [empty string]
Normal then proxy:
HTTP_CONNECTION keep-alive
HTTP_CONNECTION [empty string]
Normal then proxy:
HTTP_HOST www.pickrent.com
HTTP_HOST www.pickrent.com:80" target="_blank">www.pickrent.com:80
Normal then proxy:
HTTP_REFERER [empty string]
HTTP_REFERER http://www.pickrent.com/misc
Looking at the differences couldn't I just look at the HTTP_HOST to see if it CONTAINS '80'?
@ray I have not tried that yet.
I would have thought others with CF sites would have a similar issues as mine and there would be code out there in use to detect proxies.
https://free.megaproxy.com/go/_mp_framed?http://ww...
Based on what you identified, I'm not sure where to go. Sorry that didn't work out so great for you.
They'll give you very accurate information on an IP; I'm not just talking about the usual country & roughly the nearest state/county data; real "this is where they are" and a confidence factor with the data too :)
They also tell you things like the speed of the link, type of link (adsl,cable,satellite,etc) and proxy type (public, private, aol, etc).
Could be very useful for you. Remember that not everyone behind a proxy is bad. Some people have to use a proxy from their company. I'd recommend you give a confidence factor to the order based on multiple attributes.
Something that has proven to be quite cheap & effective is if you're taking an order on your site then you're probably taking their address. You could use the free GeoLite city DB (http://www.maxmind.com/app/geolitecity) and then do a distance between their IP location and their address. If it's more than say 50miles then minus 10 from the confidence factor. Simple, free & very effective. (NB The key is not to rely on any one attribute!)
Disclaimer: I do NOT work for either of those companies!
http://www.pickrent.com/misc/geoip.cfm
It works really well.
it flags the order as a potentially placed behind a proxy.
So far this method has thrown up red flags a few times on orders we would have otherwise shipped. Its not elegant, but it works great!
Interesting approach, I might have to try that with my next scammer. Thanks.
So, first of all, code like bellow
<cfif cgi.HTTP_X_FORWARDED_FOR neq "">
<h4>You ARE coming from a proxy.</h4>
<CFELSE>
<h4>You are NOT coming from a proxy.</h4>
</cfif>
won't have any chance to see between cgi variables. i have testing for weeks with various platforms and different versions of ACF and Railo 3.2 final too. Strage thing is that on the same apache instance a simple code like from the first post or, even better one like:
srv#cat testp.php
<?php
if(isset($_SERVER['HTTP_X_FORWARDED_FOR']) ||($_SERVER['HTTP_USER_AGENT']=='') || ($_SERVER['HTTP_VIA']!=''))
{
die("Don't use proxies, please.");
}
?>
will act like it is suppose to do. Note HTTP_VIA variable which apears only when it is a matter of anon or high-anon proxy server.
Second, Garrett Johnson gave us a clue maybe without knowing (no ofence please). So, have you ever has to install, running and administrate a proxy server before, even for a small lan ? I have few years ago and still remember something about "little" SQUID proxy server. Basicly for everyone who's goingo to use proxy server must
put proxy ip and port into browser connection dialog .. etc (sorry for this long explanation i am sure all of you have know already).
So, if you can not access header values for those variables via cgi dump what if we reverse the process ? We still have access to remote_addr and remote_host values. Now, i just want to test if remote_addr ip it is a proxy or not. How ? Trying to connect ot it. Remember that a proxy server must accept connection, right ? Well...
<!-- define function to check connection; it will return true or false if it could connect or not --->
<cfscript>
function checkMe(host,port) {
connection = createObject("java", "java.net.Socket");
connection.init(host, port);
connected = connection.isConnected();
return connected;
}
</cfscript>
<cftry>
<cfoutput>
<!--- define a variable whitch hold remote address and a variable for counting open ports --->
<cfset ip="#CGI.REMOTE_ADDR#" />
<cfparam name="q" default="0" />
<!--- checking remote ip connection within well-known range of ports --->
<cfif checkMe(#ip#,80)>
<cfset p1 = true />
<cfset q = 1 />
</cfif>
<cfif checkMe(#ip#,8080)>
<cfset p2 = true />
<cfset q =q+1 />
</cfif>
<cfif checkMe(#ip#,3128)>
<cfset p3 = true />
<cfset q =q+1 />
</cfif>
</cfoutput>
<!--- here leave empty in case this is not a proxy not to show anything --->
<cfcatch type="Any">
</cfcatch>
</cftry>
<!--- display and parsing the results
it is very basic in order to see on whitch port remote ip accept connection;
--->
<cfoutput>
<cfif IsDefined("p1")>
proxy on port 80: #p1#<br />
<cfelse>
no proxy on port 80<br />
</cfif>
<cfif IsDefined("p2")>
proxy on port 8080: #p2#<br />
<cfelse>
no proxy on port 8080<br />
</cfif>
<cfif IsDefined("p3")>
proxy on port 3128: #p3#<br />
<cfelse>
no proxy on port 3128<br />
</cfif>
</cfoutput>
<!--- then just logical detection --->
<cfif IsDefined("variables.q") AND variables.q NEQ 0>
<h2>No proxy allowed here, mate!</h2>
<cfelse>
<!--- normal processing page code as visitor it is not using a proxy --->
</cfif>
Obviously this method could be more elaborate incorporated into a CFC where to just pass only CGI.REMOTE_ADDR and wait for a boolen answer.
Hope this helps; If any has anotjer suggestion....
best regards from Romania
[Add Comment] [Subscribe to Comments]