checkrequest更适合防恶意请求,因其可在路由解析前介入请求生命周期,支持伪造头检测、行为特征分析和token多因子校验,而trusthosts仅做基础host白名单校验。

为什么 app\common\middleware\CheckRequest 比 app\http\middleware\TrustHosts 更适合防恶意请求
ThinkPHP 默认中间件只做基础信任判断,比如 TrustHosts 只校验 Host 头是否在白名单,对伪造 X-Forwarded-For、重复提交、非常规 User-Agent 等毫无防御力。自定义拦截器必须介入请求生命周期早期,在路由解析前完成过滤。
实操建议:
-
CheckRequest应继承think\Middleware,并在app/middleware.php中注册为全局中间件(非局部),确保所有请求必经此关 - 不要在
handle()里调用$next($request)后再判断——此时控制器已执行,拦截失效 - 务必用
$request->header()而非$_SERVER读取头信息,避免绕过 ThinkPHP 的 header 规范化处理
如何识别并拦截高频恶意请求(如扫描器、爆破)
真实攻击往往表现为单位时间内大量不同路径的 GET 请求,或固定参数的 POST 尝试。单纯限速不够,需结合行为特征。
实操建议:
- 用
cache()->get('req_ip_'.$request->ip())统计 60 秒内请求数,阈值设为 30;超过则返回429 Too Many Requests - 对
/admin/、/api/user/login等敏感路径,额外检查Content-Type是否为application/json或application/x-www-form-urlencoded,拒绝text/plain类型 - 若
$request->header('User-Agent')为空或含sqlmap、nuclei、gobuster等字符串,直接中断
checkToken() 验证失败时,为什么不能只 redirect 而要终止响应
重定向(redirect())只是发一个 302 响应,客户端仍可继续发送原始请求;而真正的防护必须让这次请求彻底“不往下走”。
实操建议:
- 验证失败时,统一用
return response('', 403)->header('X-Blocked', 'token_invalid'),避免泄露内部逻辑 - Token 校验不要依赖前端传来的
X-Token单一字段,应组合ip + uri + timestamp生成服务端签名,防止 token 复用 - 若使用
think\facade\Cache存 token,key 必须包含$request->ip(),否则共享缓存下 A 用户 token 可被 B 用户撞中
为什么 input('post.') !== input('post', '') 是常见坑点
ThinkPHP 的 input() 函数对空数组、空字符串、null 的处理极不一致,尤其在表单提交场景下,极易导致恶意请求绕过空值校验。
实操建议:
- 永远用
input('post.param/s', '', FILTER_SANITIZE_STRING)显式指定过滤器,而不是依赖默认行为 - 对关键字段如
username、password,必须用!empty(input('post.username'))判断,而非input('post.username') !== ''(前者能拦住null和[]) - 如果接口允许 JSON body,需手动解析:
json_decode($request->getContent(), true) ?: [],因为input('post.')对 raw body 无效
真正难的不是写拦截逻辑,而是确认每个 input() 调用背后的数据来源是否可控、每个 header() 是否经过规范化、每个缓存 key 是否绑定了当前请求上下文。漏掉任意一环,攻击者就能从缝隙里挤进来。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











