如何在AWS私有/负载均衡器IP环境下检测TOR浏览器
你的问题核心在于AWS环境下后端服务器无法直接获取用户的真实IP,而是拿到了负载均衡或私有内网IP,导致原有的TOR检测逻辑失效。其实不需要检测AWS私有IP来判断,正确的思路是先获取用户真实IP,再验证该IP是否属于TOR出口节点,下面是具体实现步骤:
第一步:获取用户的真实IP
AWS的负载均衡(如ALB、NLB)会将用户的真实IP放在X-Forwarded-For HTTP请求头中转发给后端服务器,所以你需要从这个头里提取用户IP,而不是依赖$_SERVER['REMOTE_ADDR'](这个值是负载均衡的IP)。
代码示例(PHP):
// 优先从X-Forwarded-For提取用户真实IP,兼容多个代理的情况 function getRealUserIp() { $ip = $_SERVER['REMOTE_ADDR']; if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { // X-Forwarded-For可能包含多个IP(格式:客户端IP, 代理1IP, 代理2IP...),取第一个有效IP $ipList = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']); foreach ($ipList as $ipCandidate) { $ipCandidate = trim($ipCandidate); // 排除私有/内网IP,确保拿到的是公网用户IP if (!filter_var($ipCandidate, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) { continue; } $ip = $ipCandidate; break; } } return $ip; }
第二步:验证用户IP是否为TOR出口节点
TOR官方提供了两种可靠的验证方式,推荐优先使用DNSBL(DNS黑名单)方式,无需维护本地节点列表:
方式1:使用TOR官方DNSBL服务
TOR运营了exitlist.torproject.org的DNSBL服务,你可以通过反向IP查询来验证用户IP是否属于TOR出口节点:
function isUsingTor() { $userIp = getRealUserIp(); if (!filter_var($userIp, FILTER_VALIDATE_IP)) { return false; } // 构造反向IP的DNS查询地址 $reverseIp = implode('.', array_reverse(explode('.', $userIp))); $dnsQuery = $reverseIp . '.exitlist.torproject.org'; // 执行DNS查询,若返回127.0.0.2则说明是TOR出口节点 $dnsResult = gethostbyname($dnsQuery); return $dnsResult === '127.0.0.2'; }
注意事项:
- 确保你的AWS后端服务器可以正常解析外部DNS(默认VPC配置是允许的,如果是自定义VPC需要检查安全组和NACL规则)。
- 生产环境中建议给DNS查询添加超时处理,避免因DNS服务不可用导致请求阻塞,可以使用
dns_get_record配合stream_set_timeout,或者借助第三方DNS客户端库。
方式2:本地缓存TOR出口节点列表
如果你不想依赖外部DNS服务,可以定期从TOR官方获取出口节点列表并本地缓存,然后对比用户IP:
- 定期下载TOR官方的出口节点列表文件,提取所有IP。
- 将IP存储在本地缓存(如Redis、文件或数据库),建议每1-2小时更新一次(TOR出口节点会动态变化)。
- 将用户真实IP与缓存的IP列表对比,判断是否为TOR用户。
关键误区纠正
你提到的"检测AWS私有IP来判断TOR"是没必要的,因为AWS私有IP是你的服务器所在内网的IP,和用户是否使用TOR没有任何关联。问题的核心是无法获取用户真实IP,解决这个问题后,用常规的TOR出口节点验证逻辑即可正常工作。
另外,确保你的AWS负载均衡已经配置了转发真实IP:对于ALB,默认会自动添加X-Forwarded-For、X-Forwarded-Proto等头;如果是EC2实例直接暴露(不推荐),则$_SERVER['REMOTE_ADDR']就是用户真实IP。
内容的提问来源于stack exchange,提问作者Lijo Abraham

