thinkphp无内置恶意请求防火墙,需靠路由前执行的中间件组合防护;trusthosts仅校验host头,无法防御伪造header、扫描器探测等攻击。

ThinkPHP 本身不提供“开箱即用”的恶意请求防火墙,防不住直接伪造的 POST、扫描器探测或走私请求——必须靠中间件组合拦截,且关键逻辑必须在路由解析前执行。
为什么 TrustHosts 中间件防不住恶意请求
TrustHosts 只校验 Host 请求头是否在白名单里,对以下情况完全无效:
- 攻击者用
cURL伪造合法Host,同时传X-Forwarded-For: 127.0.0.1绕过 IP 限流 - 扫描器批量请求
/admin、/api/user/login,Host完全合规 - 空
User-Agent或含sqlmap/nuclei的请求照常进入控制器
它只适合部署在可信内网网关后作兜底,不能当安全屏障。
CheckRequest 中间件必须在路由前执行
自定义中间件如 app\common\middleware\CheckRequest 要生效,必须满足三个硬性条件:
- 注册为全局中间件(写进
app/middleware.php的数组头部),不能只挂到某个路由组 -
handle()方法里**不能先调用$next($request)再判断**——此时控制器已执行,拦截毫无意义 - 读取请求头必须用
$request->header('X-Forwarded-For'),而非$_SERVER['HTTP_X_FORWARDED_FOR'],否则在 Swoole/FastCGI 模式下可能为空或被污染
典型错误写法:if (!checkToken()) { return redirect('/login'); } —— 重定向只是发个 302,原始请求照样往下走;正确做法是直接 return response('', 403)->header('X-Blocked', 'token_invalid') 终止响应。
高频请求识别不能只靠计数
单纯统计 IP 每分钟请求数(比如 cache()->get('req_ip_'.$request->ip()))容易误伤办公网用户,也防不住换代理的扫描器。真实有效的策略要叠加行为特征:
- 对
/admin/、/api/user/login等路径,额外检查Content-Type:拒绝text/plain,只放行application/json或application/x-www-form-urlencoded - 若
$request->header('User-Agent')为空,或含python-requests、curl、httpie,记录日志并限流,不直接拦截(避免被 UA 随机化绕过) - 敏感接口触发验证码前,先检查客户端是否携带有效
thinkphp_tokenCookie —— 真实用户有会话,多数爬虫连 Cookie jar 都不维护
所有缓存 key 必须带时间分片,例如 'rate_'.date('i').'_'.$request->ip(),否则 Redis 单 key 过热会导致性能抖动。
上传和表单提交的两个致命坑点
这两个场景最容易被绕过,且漏洞一旦触发就是 RCE 或越权:
-
input('post.')和input('post', '')行为完全不同:input('post.')对空数组返回null,而input('post', '')返回空字符串——攻击者传空数组就能绕过非空校验。务必用input('post.param/s', '', FILTER_SANITIZE_STRING)显式指定过滤器 - 表单必须加
@csrf指令生成__token__字段,且确保think\middleware\ValidateToken已启用;光用 POST 请求或前端 JS 校验毫无意义,CSRF 攻击本质就是伪造合法 POST
最后提醒一句:所有中间件里涉及 IP 判断的地方,Request::ip() 默认会读 X-Forwarded-For,但这个头在无可信代理时完全可伪造。生产环境要么设 'trusted_proxies' => ['127.0.0.1'],要么重写逻辑强制只用 $_SERVER['REMOTE_ADDR']。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











