必须在控制器执行前用前置中间件拦截非法请求:CheckHost校验Host头白名单(含端口),CheckIpBlacklist查缓存IP黑名单,二者均置于middleware.php最前端;Referer校验可统一或按路径精细化控制,统一用abort()保留日志。

ThinkPHP 8.0项目上线后遭遇大量伪造Host头的扫描请求、非法Referer触发的资源盗链、未授权IP直连后台接口,必须在控制器执行前就切断这些请求流——不能等路由解析完成,更不能让业务逻辑参与判断。
前置中间件拦截非法Host头
第一步:执行命令生成中间件文件:php think make:middleware CheckHost
第二步:打开app/middleware/CheckHost.php,在handle()方法开头读取真实Host值:$host = $request->header('host') ?: $request->host();(代理环境兼容写法)
第三步:从配置读取白名单并校验:if (!in_array($host, config('domain.whitelist', []))) { return response('Forbidden', 403); }。注意:白名单必须包含完整域名+端口(如admin.example.com、localhost:8000),【漏掉端口会导致本地开发环境拦截失败】
第四步:将该中间件置于app/middleware.php全局数组最前端,确保它在路由解析前执行——否则非法请求已进入路由匹配流程,拦截失去意义。
拦截非预期Referer来源
方法一:直接读Header校验
在同一个CheckHost中间件中追加:$referer = $request->header('referer'); → 若$referer为空或不在白名单内(如['https://admin.example.com', 'https://app.example.com']),直接return response('', 403)。
方法二:对特定路径精细化控制
仅拦截/api/export类高风险接口:if ($request->path() === 'api/export' && !str_starts_with($referer, 'https://admin.example.com')) { abort(403); }。这一步不用response()而用abort(),因为abort()会触发框架统一异常处理流程,保留日志记录能力。
IP黑名单实时拦截
创建独立中间件CheckIpBlacklist,在handle()中获取客户端真实IP:$ip = $request->ip(true);(启用true参数识别X-Forwarded-For)
查询缓存中的黑名单:$blacklist = cache('ip_blacklist', []);
若in_array($ip, $blacklist)成立,立即返回:return response('Blocked IP', 403)->header('X-Blocked-By', 'IPFilter'); —— 【不要用die()或exit(),会跳过框架响应生命周期】
这一步操作起来很简单,直接把IP写入缓存就行,但要注意缓存键名统一为ip_blacklist,避免多处维护不同键。
前置拦截与权限中间件协同顺序
在app/middleware.php中,中间件执行顺序决定拦截层级:
第一层:安全类前置(CheckHost、CheckIpBlacklist)→ 必须放在最前,过滤原始恶意流量
第二层:认证类前置(Auth、JwtVerify)→ 在安全层之后,确保用户身份可信
第三层:业务校验类(RateLimit、CheckTenantId)→ 依赖前两层结果,只对合法请求做频控或租户隔离
绝对禁止把Auth中间件放在CheckHost之前——否则非法Host请求会先触发Auth的Session初始化,造成无意义资源消耗。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











