PHP项目网络代理IP如何识别拦截访问请求

wen PHP项目 22

本文目录导读:

PHP项目网络代理IP如何识别拦截访问请求

  1. 方法一:检查常见的代理请求头(最基础)
  2. 方法二:获取用户真实IP并检查IP黑名单(推荐)
  3. 方法三:检测HTTP请求的“签名”差异(高级)
  4. 方法四:基于频率和行为的动态限制(非直接识别IP性质)
  5. 综合建议(实战部署流程)
  6. 注意事项

在PHP项目中识别和拦截通过代理IP发起的访问请求,通常涉及检测请求头检查IP黑名单(如已知的代理/数据中心IP段)以及使用第三方API,以下是几种常见且有效的实现方法:

检查常见的代理请求头(最基础)

代理服务器(尤其是透明代理或匿名代理)通常会在HTTP请求头中添加特定的字段,你可以检查这些字段的存在性,但这只能拦截部分非高匿代理(如透明代理)。

<?php
function isUsingProxyByHeaders() {
    $proxyHeaders = [
        'HTTP_X_FORWARDED_FOR',
        'HTTP_X_FORWARDED',
        'HTTP_X_REAL_IP',
        'HTTP_CLIENT_IP',
        'HTTP_X_CLUSTER_CLIENT_IP',
        'HTTP_FORWARDED_FOR',
        'HTTP_FORWARDED',
        'HTTP_VIA',           // 代理服务器常用
        'HTTP_X_PROXY_ID',
        'HTTP_PROXY_CONNECTION'
    ];
    foreach ($proxyHeaders as $header) {
        if (isset($_SERVER[$header]) && !empty($_SERVER[$header])) {
            // 某些情况下,这些头可能由合法反向代理(如Nginx)设置,
            // 需要确认你的服务器架构是否信任这些头。
            return true; // 疑似代理
        }
    }
    return false;
}
// 使用示例
if (isUsingProxyByHeaders()) {
    http_response_code(403);
    echo "Access denied: Proxy detected.";
    exit;
}

注意:

  • 如果使用了CDN(Cloudflare)或反向代理(Nginx),HTTP_X_FORWARDED_FOR 等头会被正常添加,会导致误杀,此时需要在Nginx层先清除外来不可信的 X-Forwarded-For,或只在没有反向代理时使用该方法。

获取用户真实IP并检查IP黑名单(推荐)

代理IP通常来自数据中心或特定云服务商(如AWS、阿里云、腾讯云、DigitalOcean、Linode等),你可以维护一份已知代理/数据中心IP段列表,或者调用第三方服务查询IP的“风险”属性。

获取客户端真实IP(处理代理链)

<?php
function getClientRealIP() {
    $ip = '';
    // 优先检查 Cloudflare (如果用了)
    if (isset($_SERVER['HTTP_CF_CONNECTING_IP'])) {
        $ip = $_SERVER['HTTP_CF_CONNECTING_IP'];
    }
    // 标准代理头(需确保来源可信,否则易伪造)
    elseif (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
        $ips = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
        $ip = trim($ips[0]); // 取第一个(最靠近客户端)
    }
    elseif (isset($_SERVER['HTTP_X_REAL_IP'])) {
        $ip = $_SERVER['HTTP_X_REAL_IP'];
    }
    elseif (isset($_SERVER['REMOTE_ADDR'])) {
        $ip = $_SERVER['REMOTE_ADDR'];
    }
    // 验证是否为合法IP
    if (filter_var($ip, FILTER_VALIDATE_IP)) {
        return $ip;
    }
    return '0.0.0.0';
}

检查IP是否在代理IP黑名单中(本地数据库 + 第三方API)

方式1:本地维护IP段数据库(如ip2location + proxy database)

<?php
// 假设你已经有一个本地数据库或文件包含可疑CIDR(如 103.21.244.0/22)
function isProxyIP($ip) {
    $proxyCIDRs = [
        '103.21.244.0/22',  // Cloudflare?
        // 更多数据中心IP段...
    ];
    foreach ($proxyCIDRs as $cidr) {
        if (ipInCIDR($ip, $cidr)) {
            return true;
        }
    }
    return false;
}
// 辅助函数:判断IP是否在CIDR范围内
function ipInCIDR($ip, $cidr) {
    list($subnet, $mask) = explode('/', $cidr);
    if (!$mask) $mask = 32;
    $ipLong = ip2long($ip);
    $subnetLong = ip2long($subnet);
    $maskLong = -1 << (32 - $mask);
    return ($ipLong & $maskLong) == ($subnetLong & $maskLong);
}

方式2:调用第三方API(推荐,更实时但需付费)

<?php
function isProxyByAPI($ip) {
    $apiKey = 'YOUR_API_KEY';
    // 以 ipqualityscore 为例
    $url = "https://ipqualityscore.com/api/json/ip/{$apiKey}/{$ip}?strictness=1";
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_TIMEOUT, 5);
    $response = curl_exec($ch);
    curl_close($ch);
    if ($response) {
        $data = json_decode($response, true);
        if (isset($data['proxy']) && $data['proxy'] === true) {
            return true; // 是代理/VPN
        }
        // 同时可检查 vpn, tor, crawler 等字段
    }
    return false;
}

常用第三方代理检测API:

  • IP2Location Proxy Database (下载本地数据库)
  • ipqualityscore
  • AbuseIPDB
  • MaxMind (GeoIP2 匿名IP数据库)
  • Cloudflare (Threat Intelligence)

检测HTTP请求的“签名”差异(高级)

代理服务器有时会修改客户端的一些行为特征,可以通过对比检测:

  1. 检查Accept-Language是否合理(代理可能不发送或错误发送)
  2. 检查时间戳/HTTP头顺序(某些代理会重组请求头)
  3. 检测WebSocket支持(真实浏览器通常支持,简单爬虫可能不支持)
  4. JavaScript挑战(CAPTCHA):在关键操作前弹出简单的JavaScript验证(如验证鼠标移动轨迹、加载图片),只有真实浏览器能通过,代理IP脚本几乎无法完成。

简单示例(Js挑战): 页面加载后,前端通过JS发送一个带时间戳和计算结果的请求到后端验证,如果后端没收到这个请求,视为非浏览器行为,进而拒绝。

基于频率和行为的动态限制(非直接识别IP性质)

代理IP通常用于批量请求,可以结合速率限制(Rate Limiting)行为异常检测来拦截:

  • 同一IP短时间大量请求同一个API
  • 请求间隔极其规律(秒级间隔,无随机性)
  • 请求的User-Agent单一或异常
  • 同时产生大量不同Session但IP相同

使用Redis内存缓存记录IP请求计数:

<?php
$ip = getClientRealIP();
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$key = "rate_limit:{$ip}";
$current = $redis->incr($key);
if ($current > 60) { // 每分钟60次
    http_response_code(429);
    echo "Too many requests";
    exit;
}
$redis->expire($key, 60);

综合建议(实战部署流程)

  1. 优先使用CDN(如Cloudflare):Cloudflare会自动过滤大量恶意代理和爬虫,你只需要信任 CF-Connecting-IP 头,之后在应用层做简单检测即可。
  2. Nginx层配合:在Nginx中先清除不可信的 X-Forwarded-For,只保留CDN或内部反向代理设置的版本:
    # Nginx 配置
    real_ip_header CF-Connecting-IP; # 如果用了Cloudflare
    set_real_ip_from 0.0.0.0/0;
  3. 在PHP中执行
    • 获取真实IP(从可信来源如 CF-Connecting-IPREMOTE_ADDR)。
    • 检查IP是否在黑名单(本地CIDR列表 + 第三方API做二次验证)。
    • 结合速率限制和行为检测。

最终简化版代码示例:

<?php
$realIP = getClientRealIP(); // 上述函数
// 1. 快速本地黑名单检测
if (isProxyIP($realIP)) {
    exit('Proxy detected. 403');
}
// 2. 第三方API检测(非高频请求时调用,或缓存结果)
$cacheKey = "proxy_check:{$realIP}";
$cached = apcu_fetch($cacheKey);
if ($cached === false) {
    $isProxy = isProxyByAPI($realIP);
    apcu_store($cacheKey, $isProxy, 3600); // 缓存1小时
} else {
    $isProxy = $cached;
}
if ($isProxy) {
    exit('VPN/Proxy detected. 403');
}
// 3. 速率限制
rateLimit($realIP);
// 正常业务逻辑...

注意事项

  • 误杀风险:企业出口的NAT IP可能被误判为代理(例如同一公司多人共用公网IP),可适当降低严格度(如放宽频率限制)。
  • 性能:不要对每个请求都调用第三方API,务必使用缓存(Redis / APCu)。
  • 法律合规:部分国家/地区对拦截代理IP有注册要求(如防火墙合规),注意查看当地法律。

希望这套方案能帮你有效识别和拦截代理IP的访问!

抱歉,评论功能暂时关闭!