Referer校验常失效因客户端可伪造,仅适合防手误;Origin才可靠,需校验其是否在白名单中,且须配置反向代理透传、用中间件分路径精准拦截。

Referer 校验为什么经常失效
因为 Referer 是客户端可随意伪造的 HTTP 头,浏览器、curl、Postman 甚至前端 JS 都能轻易改写。ThinkPHP 的 request()->header('referer') 拿到的值本身就不具备可信度,校验它只适合防手误或低门槛爬虫,不能用于权限控制或敏感操作拦截。
常见错误现象:if (strpos($referer, 'yourdomain.com') !== false) 直接判断,结果被 https://evil.com/yourdomain.com/attack 绕过;或者没做空值判断,$referer 为 null 或空字符串时抛出 Warning。
- 必须先用
isset()或!empty()检查Referer是否存在 - 匹配域名要用 parse_url() 提取 host,避免子串匹配陷阱
- 生产环境别单独依赖 Referer,它只是辅助信号
Origin 头才是跨域请求的可靠依据
Origin 由浏览器在跨域请求(如 fetch、XMLHttpRequest)中自动添加,且无法被前端 JS 修改——这是浏览器安全策略强制保证的。ThinkPHP 中可用 request()->header('origin') 获取,但注意:同源请求(如页面内表单提交)不会携带 Origin,此时该值为空。
使用场景很明确:只在校验 API 接口(尤其是 POST/PUT/DELETE)是否来自合法前端域名时才有效。比如管理后台调用用户删除接口,必须确认 Origin 是 https://admin.yourapp.com。
-
Origin值格式固定为协议://域名:端口(端口省略时为默认端口),直接字符串比对即可 - ThinkPHP 6+ 默认不拦截非法
Origin,需手动加中间件或控制器逻辑校验 - 若后端启用了 CORS,
Access-Control-Allow-Origin设置会影响前端能否读取响应,但不影响服务端对Origin的校验逻辑
如何在 ThinkPHP 控制器里安全地同时检查两者
实际项目中,你往往既想拦住明显异常的跨域请求,又想兼容同源表单提交——这时需要分路径处理,而不是一刀切。核心原则:允许无 Origin(同源),但若有 Origin,就必须合法;Referer 仅作补充参考,不参与准入决策。
示例代码片段(放在控制器方法开头):
$origin = $this->request->header('origin');
$referer = $this->request->header('referer');
// 有 Origin 必须校验
if ($origin && !in_array($origin, ['https://admin.yourapp.com', 'https://app.yourapp.com'])) {
throw new HttpException(403, 'Invalid Origin');
}
// Referer 仅记录或调试用,不用于拒绝请求
if ($referer) {
\think\Log::info('Referer detected', ['url' => $referer]);
}
- 不要用
$_SERVER['HTTP_ORIGIN'],ThinkPHP 封装的request()->header()更统一、更安全 - 白名单域名建议配置在
config/app.php里,避免硬编码 - 如果用了 Nginx 反向代理,确保
proxy_set_header Origin $http_origin;已配置,否则Origin会丢失
中间件方式统一处理更稳妥
把来源校验逻辑抽成中间件,避免每个控制器重复写。ThinkPHP 6+ 的中间件生命周期早于控制器执行,适合做前置拦截。但要注意:中间件默认对所有路由生效,需用 $request->url() 或路由标识做条件过滤,否则登录页、静态资源也会被误拦。
关键点在于区分「需要校验的接口」和「无需校验的页面」。比如只对 /api/v1/user/delete 这类操作接口校验,而放行 /login、/public/*。
- 注册中间件时用闭包或路由分组绑定,别全局
App::middleware - 中间件里用
$request->isAjax()或$request->isPost()辅助判断请求类型,提高精度 - 返回 403 时别暴露过多信息,例如不要返回具体哪个头不合法,防止被探测
实际部署时最容易被忽略的是反向代理层对请求头的清洗——Nginx 或 CDN 可能默认 strip 掉 Origin 和 Referer,这时候后端永远拿不到,校验就形同虚设。得逐层确认 header 是否透传,而不是只盯着 PHP 代码。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











