ThinkPHP 中仅靠 User-Agent 防爬效果有限,应结合中间件、白名单配置、行为分析与频控等多层防护;UA 判断须用 stripos(),避免硬编码于控制器,禁用 DB 查询白名单。

ThinkPHP 里靠 User-Agent 字符串做“防爬”根本拦不住真实爬虫,它只适合快速放行可信客户端或标记明显异常流量——比如空 UA、含 python-requests 却走 Web 路由的请求。
ThinkPHP 6+ 怎么取和判断 User-Agent
用 request()->header('user-agent') 获取值,别用 $_SERVER['HTTP_USER_AGENT'] 直接读,否则中间件里可能拿不到(尤其启用了 Swoole 或 FastCGI 模式时)。匹配必须用 stripos(),不是 == 或正则全匹配——因为合法 UA 变体太多,比如 Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) 和 Mozilla/5.0 (iPad; CPU OS 17_5 like Mac OS X) 就不该被拆成两个白名单项。
- 白名单配置建议放在
app/extra/spider.php,内容为return ['Mobile Safari', 'Chrome', 'WeChat']; - 移动端 UA(如微信内置浏览器)和桌面端要分开看,别把
MicroMessenger当爬虫误杀 - 空字符串、纯数字(如
123456)、或含curl/httpie/python-requests的 UA,应直接记录日志并限流,不建议halt()——避免被扫描器批量触发崩溃
为什么不能在控制器里硬写 UA 判断逻辑
控制器是业务入口,不是流量筛子。把 UA 校验塞进控制器会导致:复用难(每个接口都得复制一遍)、升级难(TP 升级后中间件生命周期变化,控制器里逻辑容易失效)、排查难(日志分散,无法统一统计异常 UA 分布)。
- 正确做法是写一个中间件,比如
app/middleware/UserAgentFilter.php,在handle()里做判断 - 中间件注册到全局(
app/middleware.php)或按路由分组绑定,确保所有 Web 路由都经过 - 别在中间件里调用数据库查白名单——配置文件读取快,DB 查询会拖慢首字节响应时间
UA 合法但仍是爬虫?这时候该看什么
如果一个请求的 User-Agent 完全合法(比如 Chrome 最新 UA),但没带 Cookie、没 Referer、X-Requested-With 为空、JS 行为字段(如页面加载到点击间隔
立即学习“PHP免费学习笔记(深入)”;
- ThinkPHP 自带的
think\facade\Request不会验证 UA 真实性,它只是原样返回 header 值 - 验证码触发点不能只卡在提交按钮,得前置:比如登录页 JS 注入
_ts隐藏字段,服务端比对request()->post('_ts')和当前时间差 - 检查
request()->cookie('thinkphp_token')是否存在且未过期——真用户有会话,多数爬虫连 Cookie jar 都懒得维护
真正容易被忽略的是:UA 白名单一旦写死,就变成攻击者的路标。他们只要抓一次你放行的请求,抄下 UA 字符串,就能绕过整层校验。所以 UA 校验永远只是第一道轻量过滤,后面必须叠加行为分析、频次控制、JS 挑战这些不可伪造的维度。



















