thinkphp静态资源防盗链需nginx配置valid_referers白名单并确保url不被asset()改写;token校验须由php中间件完成,签名基于$uri+$t+$s,严格过滤参数并禁用敏感错误提示。

ThinkPHP 静态资源怎么加 Referer 白名单?
Referer 验证是最轻量的防盗链手段,但 Nginx 层直接拦截前,必须确保 ThinkPHP 不主动改写静态资源 URL(比如通过 asset() 生成带时间戳的链接),否则白名单规则会频繁失效。
实操建议:
- Nginx 配置中用
valid_referers明确列出允许的域名,不要用none或blocked,它们容易被伪造或误判 - ThinkPHP 的静态资源路径要走标准子目录(如
/static/js/app.js),避免放在/public外或用路由重写暴露真实路径 - 测试时用 curl 模拟不同 Referer:
curl -H "Referer: https://evil.com" https://yoursite.com/static/logo.png,观察是否返回 403
为什么 Nginx 的 $request_uri 不适合做 Token 签名验证?
动态 Token 防盗链需要签名参数参与计算,而 $request_uri 包含原始查询字符串(含签名本身),直接用于 HMAC 计算会导致签名循环依赖——你验的是自己刚拼进去的东西。
正确做法是拆出干净路径和参数:
- 用
$uri(不含 query) +$arg_t(时间戳) +$arg_s(签名)三者组合校验 - ThinkPHP 中生成链接时,调用
hash_hmac('sha256', $uri . $expire, $secret),确保服务端校验逻辑完全一致 - 注意 Nginx 的
map指令不支持调用加密函数,Token 校验必须由 ThinkPHP 的中间件或 Nginx 的auth_request子请求完成,不能纯靠 rewrite
Token 过期时间写死在 Nginx 里会出什么问题?
如果在 Nginx 配置里用 set $expire 1717027200; 这类硬编码时间戳,每次更新都要 reload,而且无法按资源类型差异化控制(比如图片 2 小时、视频 10 分钟)。
更可靠的方式是让 ThinkPHP 控制过期逻辑:
- 生成链接时,URL 带
?t=1717027200&s=abc123,其中t是 Unix 时间戳,服务端只校验time() - Nginx 不解析过期时间,只转发请求;真正校验交给 ThinkPHP 中间件,便于统一日志、限流和灰度
- 避免用相对时间(如
+3600)拼接,Nginx 的add_header无法动态计算,容易因服务器时区/时间偏差导致提前失效
ThinkPHP 中间件校验 Token 时,哪些字段必须严格过滤?
用户可控的 URL 参数是攻击入口,$request->param('s') 和 $request->param('t') 必须做最小化清洗,否则可能绕过签名验证。
关键过滤点:
-
t参数只接受数字,且长度限制为 10 位(Unix 时间戳),拒绝1717027200.1或超长整数 -
s参数限定为 64 位小写十六进制(SHA-256 输出),拒绝任何非[a-f0-9]字符 - 完整签名原文必须用
$request->server('REQUEST_URI')截断后的$uri(不含 query),而非$request->url(),后者可能含路由别名或重写后路径 - 校验失败时返回 403,**不要**返回详细错误信息(如 “签名错误” 或 “已过期”),防止信息泄露辅助爆破
最易被忽略的是:Nginx 开启 gzip 后,某些旧版 ThinkPHP 的中间件可能在解压前读取原始 body,导致签名原文与客户端不一致。遇到校验总失败,先关掉 gzip_static 和 gzip 测试。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











