referer防盗链常失效因未配对if判断或忽略if作用域限制;正确配置需valid_referers定义白名单→$invalid_referer变量触发→if($invalid_referer)拦截,缺一不可。

Referer 防盗链为什么经常失效
直接在 location 块里写 valid_referers 却没效果?大概率是没配对 if 判断逻辑,或者忽略了 Nginx 的 if 作用域限制。Nginx 中 if 在 location 内虽可用,但不支持嵌套,且不能用在 limit_req 或 proxy_pass 等指令前——而防盗链恰恰依赖它触发拦截动作。
常见错误现象:
-
valid_referers写了但图片仍能被外站直接打开 - 自家页面引用也 403(漏加
none或协议不一致) - HTTPS 页面引用 HTTP 图片,或反之,导致 Referer 被浏览器清空
真正起作用的是这个组合:valid_referers 定义白名单 → $invalid_referer 变量自动设为 1 → 用 if ($invalid_referer) 拦截。缺一不可。
如何正确配置图片静态资源的 Referer 白名单
针对 .jpg、.png、.gif 等后缀,在 server 或 location 块中集中处理最稳妥:
location ~* \.(jpg|jpeg|png|gif|webp|svg)$ {
valid_referers none blocked server_names
*.example.com example.com
~\.google\.
~\.baidu\.;
if ($invalid_referer) {
return 403;
# 或返回默认占位图:rewrite ^(.*)$ /static/forbidden.png break;
}
}
关键点说明:
-
none允许直接输入 URL 访问(比如用户收藏图片链接) -
blocked允许 Referer 被移除的请求(如 HTTPS→HTTP 跳转时浏览器清空 Referer) -
server_names允许本域名所有子域名(需配合server_name设置) - 正则匹配(如
~\.google\.)注意转义点号,且必须以~开头 - 不要把
valid_referers放在if外面再写一遍——它只在当前location生效一次
为什么有时明明配了却返回 404 而不是 403
这不是 Referer 配置问题,而是 return 403 被后续规则覆盖了。典型场景是:你用了 try_files 或 alias,又在它们之后写了 if ——Nginx 会先执行 try_files 查文件,找不到就回退到 404,根本不会走到 if。
解决办法只有两个:
- 把防盗链
if块放在try_files或alias之前(推荐) - 改用
map提前定义$invalid_referer,再在try_files后用error_page 403 = @forbidden统一处理(更健壮)
顺带提醒:alias 和 root 对路径拼接逻辑不同,若用 alias,确保末尾有斜杠;否则可能因路径错位导致 404,误以为是防盗链惹的祸。
移动端和 PWA 场景下 Referer 的特殊行为
微信内置浏览器、某些安卓 WebView、PWA 的 display: standalone 模式,都会主动清空或伪造 Referer。单纯靠 valid_referers 会误杀大量合法访问。
应对策略不是放弃 Referer,而是分层控制:
- 对
User-Agent包含MicroMessenger、QQBrowser、WebView的请求,跳过 Referer 校验(用map+$http_referer判断) - 给核心图片加 token 签名(如
/img/xxx.jpg?t=123&sign=abc),服务端校验,Referer 仅作辅助 - CDN 层开启 Referer 过滤(如阿里云 CDN 的“防盗链设置”),比 Nginx 更早拦截,减轻源站压力
Referer 本质是“尽力而为”的客户端提示,不是安全边界。真要防批量爬取,得靠频率限制、User-Agent 分析、甚至 JS 挑战,而不是只盯着这一行配置。











