图片防盗链失效需逐层排查:先开启referer日志,再确认valid_referers配置在正确location块中,避免if与try_files冲突,并注意https引用http时浏览器清空referer的问题。

图片防盗链配置不生效,不是配置写错了就完事,而是得顺着请求链路一层层看——从客户端发请求、Nginx怎么匹配、怎么判断Referer、有没有被其他规则覆盖,再到日志里找证据。下面这几个点,90%的失效问题都出在这里。
Referer 日志没打开,根本看不到来源
没开 referer 日志,等于闭眼排障。Nginx 默认日志格式里不包含 $http_referer,你根本不知道浏览器到底带了什么 Referer 过来。
- 在
http块里补全日志格式,比如:log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" "$http_user_agent"'; - 确认 access_log 使用的是这个格式,且路径可写
- 重启或重载 Nginx 后,用 curl 模拟盗链请求:
curl -H "Referer: http://evil.com" https://yoursite.com/images/test.jpg,再查日志是否记录了http://evil.com
valid_referers 配置位置或范围不对
防盗链规则必须写在真正处理图片的 location 块里,不能只放在 server 根层级——Nginx 不允许在 server 级直接用 valid_referers。
- 检查图片是否真走到了你加了
valid_referers的 location。比如你配在location /images/,但实际请求是/static/img/foo.png,那就完全不命中 - 注意
valid_referers none会放行所有无 Referer 请求(如直接在地址栏输入、HTTPS 页面引用 HTTP 图片等),容易误放 - 如果用了
server_names,确保域名完全匹配:example.com≠www.example.com,建议写成valid_referers example.com www.example.com;
if 判断写在错误上下文,或被其他指令覆盖
很多人习惯这么写:
if ($invalid_referer) { return 403; }
但 if 在 location 里属于“限制性上下文”,且容易和 rewrite、try_files 等指令冲突。更隐蔽的问题是:如果前面有 try_files 或 alias 先完成了文件查找并返回,if 根本不会执行。
- 推荐把防盗链逻辑紧贴在 location 开头,且避免和 try_files 混用
- 不要在同一个 location 里既用 if 又用 rewrite last —— last 会跳转到新 location,原 if 失效
- 用
error_page 403 =200 /forbidden.jpg;替代 rewrite,语义清晰、不干扰状态码
HTTPS 页面引用 HTTP 图片,Referer 被浏览器主动清空
现代浏览器出于安全策略,从 HTTPS 页面发起对 HTTP 资源的请求时,会默认不发送 Referer(或只发 origin)。这时你的 valid_referers 即使写了域名,也匹配不到完整 Referer,结果变成 none 或空字符串。
- 查日志,如果大量 403 请求的 referer 字段是 “-” 或空,大概率是这个原因
- 解决方案不是放宽防盗链,而是统一协议:前端所有图片链接用
//domain.com/path.jpg或明确写https:// - 必要时可在 HTML 中加
<meta name="referrer" content="no-referrer-when-downgrade">控制行为(但兼容性需验证)











