PHP项目深度爬虫如何拦截站内遍历访问

wen PHP项目 26

本文目录导读:

PHP项目深度爬虫如何拦截站内遍历访问

  1. 核心防御层:频率控制 (Rate Limiting)
  2. 行为特征分析:识别遍历模式
  3. 访问鉴权与验证
  4. 服务端配置与防御
  5. 高级方案:行为指纹 + 机器学习(适合大型项目)
  6. 监控与反馈
  7. 总结:推荐组合策略(按优先级)

针对PHP项目中的深度爬虫(尤其是恶意爬虫)对站内链接进行遍历式访问(如穷举ID、遍历URL参数、抓取全站内容),可以采用以下分层次的拦截策略,兼顾性能安全性


核心防御层:频率控制 (Rate Limiting)

这是防遍历最直接、最有效的手段,根据 IP用户会话(Session) 限制单位时间内的请求数。

1 基于IP的简单计数器(适用于中小型项目)

index.php 或全局中间件中实现:

<?php
// 防遍历频率控制中间件示例
$ip = $_SERVER['REMOTE_ADDR'];
$key = 'rate_limit:' . $ip;
$limit = 60; // 每分钟允许60次请求
$window = 60; // 60秒窗口
// 使用Redis(推荐)或文件缓存
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$current = $redis->get($key);
if ($current === false) {
    $redis->setex($key, $window, 1);
} elseif ($current >= $limit) {
    // 触发限流:返回429状态码
    http_response_code(429);
    header('Retry-After: ' . $window);
    echo json_encode(['error' => '请求过于频繁,请稍后再试']);
    exit;
} else {
    $redis->incr($key);
}

2 滑动窗口算法(更精准)

避免固定窗口边界导致的突发流量穿透,可使用有序集合实现滑动窗口计数器。

function slidingWindowRateLimit($ip, $limit = 60, $window = 60) {
    $redis = new Redis();
    $redis->connect('127.0.0.1', 6379);
    $key = "sliding_ratelimit:$ip";
    $now = microtime(true);
    $redis->zRemRangeByScore($key, 0, $now - $window); // 清除过期记录
    $count = $redis->zCard($key);
    if ($count >= $limit) {
        return false;
    }
    $redis->zAdd($key, $now, $now . rand(1000,9999)); // 唯一ID
    $redis->expire($key, $window);
    return true;
}
if (!slidingWindowRateLimit($_SERVER['REMOTE_ADDR'])) {
    http_response_code(429);
    exit('频率限制');
}

行为特征分析:识别遍历模式

单纯限IP不够,因为爬虫可能使用代理池或分布式,需要分析访问模式

1 路径深度异常检测

正常用户在站内访问深度通常有限(例如3-5层),爬虫会遍历所有可能的路径。

  • 统计:记录每个会话的访问URL数量、平均深度、重复度。
  • 规则:若某IP在短时间内访问超过500个不同的URL,且路径深度超过10,则判定为遍历爬虫。

2 参数枚举检测

爬虫常通过 ?id=1,2,3...?page=1,2,3... 遍历数据。

  • 检测方法:统计同一参数名下的不同值数量,5秒内对 /product?id= 请求了100个不同ID,则标记为异常。
// 参数枚举检测示例(Redis实现)
$currentUrl = $_SERVER['REQUEST_URI'];
$path = parse_url($currentUrl, PHP_URL_PATH);
parse_str(parse_url($currentUrl, PHP_URL_QUERY), $params);
// 检查常见的遍历参数(如id、page、cat等)
foreach (['id', 'page', 'post_id', 'user_id'] as $param) {
    if (isset($params[$param])) {
        $key = "enum_detect:$path:$param:" . $_SERVER['REMOTE_ADDR'];
        $redis = new Redis();
        $redis->connect('127.0.0.1', 6379);
        $redis->sAdd($key, $params[$param]);
        $redis->expire($key, 10); // 10秒窗口
        if ($redis->sCard($key) > 20) { // 10秒内同一参数出现超过20个不同值
            // 触发拦截
            http_response_code(403);
            exit('检测到参数枚举行为');
        }
    }
}

访问鉴权与验证

1 强制登录 + 权限校验

站内遍历爬虫往往无法通过认证。

  • 要求:站内核心数据(如用户详情、订单)必须登录后访问,且通过用户ID验证是否属于当前用户。
  • 实现if ($_SESSION['user_id'] != $requested_user_id) { 拒绝访问; }

2 验证码(渐进式增强)

对于可疑请求,强制要求验证码。

  • 实现:对高频访问IP或路径参数异常IP,返回HTML验证码页面,通过后才放行。
  • 工具:Google reCAPTCHA v3(无感)或简单的图形验证码。

3 Token/Anti-CSRF 机制

爬虫往往无法携带有效的Token(除非解析页面)。

  • 方法:每个页面生成一个一次性Token,随链接参数传递(如 ?token=abc123),服务器校验Token是否存在且有效,该Token通常绑定用户会话,且一次使用后失效
  • 注意:会破坏简单的页面缓存,但能有效阻止非人工的遍历访问。
// 生成并验证页面访问Token
session_start();
$token = bin2hex(random_bytes(16));
$_SESSION['page_tokens'][] = $token;
// 在链接中添加:?ptoken=<?= $token ?>
// 页面入口校验:
if (!in_array($_GET['ptoken'] ?? '', $_SESSION['page_tokens'])) {
    exit('非法请求');
}
// 使用后移除该Token
array_splice($_SESSION['page_tokens'], array_search($_GET['ptoken'], $_SESSION['page_tokens']), 1);

服务端配置与防御

1 Nginx 层限流(推荐)

无需修改PHP代码,性能最高。

# nginx.conf
limit_req_zone $binary_remote_addr zone=anti_traversal:10m rate=30r/m;
server {
    location / {
        limit_req zone=anti_traversal burst=5 nodelay;
        # ... 其他配置
    }
    # 对敏感路径(如 /user, /product)进行更严格限制
    location ~ (/user|/product) {
        limit_req zone=anti_traversal rate=10r/m;
    }
}

2 Web Application Firewall (WAF)

通过ModSecurity、Cloudflare WAF等设置规则:

  • 规则示例:阻止同一IP在1分钟内访问超过100个不同的URL路径。
  • 自定义签名:检测URL中包含连续数字且无Referer或User-Agent异常的请求。

高级方案:行为指纹 + 机器学习(适合大型项目)

如果爬虫能模拟浏览器,单纯规则很难完全拦截,可引入行为指纹

  • 采集信息:鼠标轨迹、键盘事件、滚动速度、屏幕分辨率、canvas指纹、WebGL指纹等。
  • 评估:爬虫通常没有这些真实浏览器行为,或者行为模式固定、速度过快。
  • 方案:使用 FingerprintJS 或自建服务进行判断,对低分请求进行验证或降速。

监控与反馈

无论采用何种拦截方式,都需要日志记录报警

// 记录被拦截的请求
function logBlockedRequest($reason) {
    $log = [
        'ip' => $_SERVER['REMOTE_ADDR'],
        'time' => date('Y-m-d H:i:s'),
        'url' => $_SERVER['REQUEST_URI'],
        'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? '',
        'reason' => $reason
    ];
    // 写入文件、数据库或日志服务
    file_put_contents('/var/log/traversal_block.log', json_encode($log) . "\n", FILE_APPEND);
    // 如果某IP短时间内被频繁拦截,发送告警
}

推荐组合策略(按优先级)

优先级 策略 实现难度 效果 适用场景
1 Nginx限流 极高 所有项目,第一道防线
2 IP频率控制(Redis) 无法配置Nginx时
3 参数枚举检测 高(针对穷举ID) 公开ID访问的页面
4 Token一次性链接 极高 极端敏感数据
5 验证码/行为验证 辅助手段,用户体验折中

务必注意:过于严格的频率限制会误伤正常用户(如SEO爬虫、内部监控、批量操作工具),建议为搜索引擎爬虫(通过User-Agent识别 GooglebotBingbot 等)设置白名单。

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