通过PHP检测使用代理服务器的客户端

26

我正在寻找一种方法或途径来检测使用任何类型的代理服务器查看我的网站的客户端。我正在使用PHP / Apache……应该如何最好地做到这一点?需要检测任何代理服务器,而不是具体某一个。

编辑

我更感兴趣的是匿名代理……因为常规代理可以通过查找HTTP_X_FORWARDED_FOR轻松检测出来。

另一个编辑

试试这个:

1)访问http://kproxy.com(或任何其他免费的匿名代理网站)

2)访问:http://www.worldofwarcraft.com

3)他们能够以某种方式阻止,因为页面会报错,显示“加载样式表时出错:加载XSLT样式表时发生网络错误:http://kproxy.com/new-hp/layout/layout.xsl

我想做类似的事情,以防止代理。


你的意图是什么?是禁用缓存还是其他什么吗? - guerda
通过kproxy.com,worldofwarcraft.com对我来说加载得很好,只是缺少样式表,这可能是由于它们在HTML中的引用方式而不是某些代理阻止器导致的。 - cOle2
我们打算阻止匿名网站让用户查看我们的网站。正如上面提到的,暴雪公司通过使用样式表技巧来实现这一点。 - Kladskull
奇怪,我用火狐浏览器无法加载。 - Kladskull
我建议使用IPQualityScore(http://ipqualityscore.com),每月免费提供5000次查询,比简单的HTTP_X_FORWARDED_FOR检查要好得多。 - Bravo Delta
10个回答

26

使用以下两种 PHP 解决方案:

方法1:快速但无法使用匿名代理。

$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 $x){
    if (isset($_SERVER[$x])) die("You are using a proxy!");
}

方法二:在正常代理端口上向原始IP进行端口扫描。

$ports = array(8080,80,81,1080,6588,8000,3128,553,554,4480);
foreach($ports as $port) {
     if (@fsockopen($_SERVER['REMOTE_ADDR'], $port, $errno, $errstr, 30)) {
          die("You are using a proxy!");
     }
 }

10
我不建议使用第二种方法 - 它通常会返回错误的结果。当我们在网站上使用第三方代理检测脚本时,就曾经遇到过这样的问题。请注意,这里的“false positives”指的是错误的检测结果,即误判为使用了代理而实际上没有。 - HellaMad
4
第二种方法不仅需要很长时间,而且无法在高流量的网站上实施,还可能会引起一些访问者反病毒警报! - Silviu-Marian
HTTP_X_FORWARDED_FOR在我正常的互联网直连连接中返回了错误的结果。 - Sumedh
这个不起作用,并且在我的普通浏览器和正常的网络连接下会产生正面的结果。 - Fery Kaszoni
忘记这个头检查代码吧。我测试了数千个代理,唯一得到的头是“REMOTE_ADDR”,没有一个代理会给你任何列出的头信息。这段代码是无用的。 - Feng Jiang

20

除非他们传递特殊的头部信息(如 X-Forwarded-For 等),否则您无法检测到它。

据我所知,您必须使用黑名单。使用putty端口转发、VPN或其他更复杂的方法的用户是无法检测到的,因为他们的行为与正常用户完全相同。


有没有什么诀窍可以做到这一点?有什么不能被缓存或转发的东西吗? - Kladskull
作为服务器端开发人员,您无法看到我是通过VPN(是的,这是代理)还是通过我的真实互联网连接进行连接,没有任何诀窍。您提到的技巧只能阻止某些基于Web的匿名代理,但不能阻止使用具有putty端口转发等功能的VPS的好代理。 - TomHastjarjanto

9

Metasploit使用多种不同的技术来强制客户端系统进行直接连接(Flash、Java、QuickTime、MS Office、自定义DNS服务器中的漏洞/误用)。

另外,如果无法使客户端浏览器启动Metasploit,则可以尝试查找开放代理(端口扫描)和已知的Tor出口节点

但请不要假设代理是邪恶的并需要被阻止-有很多合法的代理,一些用户必须使用它们。

如果您遇到垃圾邮件或其他滥用流量的问题,那么仅阻止代理将无济于事。您应该寻找针对问题核心的特定解决方案(垃圾邮件过滤器、IDS),而不是假设匿名=有罪。


4
有各种付费/免费的解决方案。大多数方法是通过检查客户端IP地址来确定其是否使用代理。

付费:
Maxmind - 他们专注于诈骗检测,并有一个子类别用于代理检测。请注意,此服务现在被认为是“遗留”服务。

免费:
W I T C H - 通过查看唯一可识别的MSS值,能够检测OpenVPN。代码可在github上获取。

GetIpIntel - 使用机器学习进行代理/VPN检测,通过API查询。

安全堆栈交换上列出了另外几个免费选项。(链接)


您可以在 Google 中搜索 "IP2Proxy"。它是一种付费解决方案,具有每日更新的代理 IP 地址。 - Michael C.
我刚刚使用了IP2Proxy进行了一些测试,它并不是非常准确。根据我的经验,在付费解决方案中,blocked/maxmind表现良好,而getIPIntel是最佳的免费解决方案。 - S W
另一个值得添加到此列表的代理和VPN检测服务是IPQualityScore(https://www.ipqualityscore.com/)。他们有慷慨的免费和付费计划,代理检测非常准确,不会将IP标记为误报。 - Johnny
GetIpIntel有非常低的速率限制,而且价格非常高昂。我的应用在客户使用2个小时后就被限制了速率。 - user10398534

1

虽然话题有些陈旧,但我可能已经找到了解决方法。

它已经在我的网站上实现,我认为它对大多数情况都适用。

我的问题是被禁用户会使用可以找到的众多代理之一,使用新的电子邮件地址重新注册到我的网站。我所做的只是在注册/登录表单上进行简单的jQuery调用:

<form id="login_form" method="post" action="/#fake_login_url">
   stuff you need for the form
</form>
<script>
   $('#login_form').attr('action','real_login_form');
</script>

我假设这只能检测到从网络流量中剥离JS的代理? - sousdev
2
大多数代理服务器会替换帖子的URL,执行JS代码可以将其恢复正常。确保“real_login_form”不是明文,例如:var url ='ht'+'tp:'+'//'+'site'+'.com'+'/url' - Fabrizio

1

客户端传递给服务器的所有内容都可以进行自我配置。除了 IP 地址,您不能信任任何东西。因此,您无法检查标头数据,以确定它是代理还是普通客户端。
顺便说一下:代理的意图就是不显示为代理 :)

当然,您可以获取请求者的 IP 地址,并发送一个 http 请求,该请求将发送到代理。如果它有反应,则可能是代理;否则,它就是普通客户端。这种方法非常昂贵且不可靠。如果您的服务器请求的代理位于防火墙后面,则您将得不到答案,并认为它是普通客户端。


快速浏览一下我在“另一个编辑”下修改的示例。不知何故,暴雪能够使用一些技巧欺骗代理服务器。 - Kladskull

1

我认为这里正在发生的是一些客户端JavaScript正在尝试加载某些东西,并且可以“看到”页面正在框架内被查看。这可能是一个更有成效的探索途径-正如其他答案所指出的那样,代理有意使仅从服务器很难确定。


-1

即使这是一个老问题,我不得不检查代理,但不幸的是,没有一个答案给出了好的结果。

经过搜索,我找到了一种更好的方法。为了理解这种做法,只需创建一个带有以下代码的小页面:

 <?php
 foreach ($_SERVER as $key => $val)
 {
     echo $key."<br>\n";  
 }
 ?>

直接从您的服务器运行它。您将看到您的服务器发送的所有标头键。然后通过代理运行相同的脚本。 您将看到(取决于代理)3种可能的结果:

  1. 代理添加新的键/值
  2. 代理不发送所有原始键/值,因此有些键/值会丢失。
  3. 代理发送完全相同的键/值,但顺序不同
  4. 代理以相同的顺序发送完全相同的键/值

第四种情况可能发生,但其他情况最常见。 因此,您只需创建一个数组,其中包含来自您的服务器的键/值(基于在没有代理的情况下运行脚本时的结果),并比较来自$ _SERVER的键/值。如果您没有完全相同的键/值(少,多或其他顺序),则可以假定页面来自代理。

请注意,我同意那些说在某些情况下代理可以“合法”使用的人。


-2

我觉得回答一个8年前的帖子没有意义,但是为了将来的参考,我还是会回答。
我不知道代理,但大多数VPN(如果你使用它们)会出现某种错误页面。如果你做了类似于...

$cont = file_get_contents($_SERVER["REMOTE_ADDR"]); //the users ip
$errormsg = "nginx";
if(strpos($cont, $errormsg)){
    die("No VPN's or Proxies Allowed");
}

这很基础,你可以获取错误消息的数组并以此方式处理。
如果用户已经将80端口进行了端口转发,那么这种方法将不起作用,但我不认为普通人会这样做。


-5
我正在使用以下代码,但不确定它是否每次都能正常工作。 这只是一个想法 :)
<?php
$host = gethostbyaddr($_SERVER['REMOTE_ADDR']);
if ($host != $_SERVER['REMOTE_ADDR']) die('Proxy detected.');
?>

6
这将对许多用户失败,因为gethostaddr大多数情况下返回用户名和提供程序名称,例如:5ED042DD.dynamic.<a providerdomain>.com。 - Codebeat

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接