本文目录导读:

针对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识别 Googlebot、Bingbot 等)设置白名单。