最稳妥方案是valid_referers+ $invalid_referer + if + return 403,必须置于匹配资源的location块内,且none和blocked不可省略,否则移动端webview、内网调试及pwa离线加载将全部失败。

直接结论:用 valid_referers + $invalid_referer + if + return 403 是最稳妥、开箱即用的方案,但必须写在匹配资源的 location 块里,且 none 和 blocked 不能删——漏掉它们,移动端 WebView、内网调试、PWA 离线加载全会 403。
valid_referers 必须放在 location 块里才生效
它只在 server 或 location 块中起作用,写在 http 块顶层完全无效。Nginx 启动时不报错,但所有防盗链逻辑形同虚设。
- 错误写法:
http { valid_referers none blocked example.com; }→ 白配 - 更隐蔽的坑:
location /里写valid_referers,结果 HTML、JS、API 请求也受 Referer 限制,登录跳转失败、AJAX 报 403 - 正确做法:按资源类型切分,例如只对图片/视频/PDF 生效:
location ~* \.(jpg|png|webp|mp4|pdf)$
none 和 blocked 不是“放水”,而是真实访问必需
这两个参数对应两类高频合法流量,不是可选项:
-
none:请求头里压根没Referer字段,比如用户直接在浏览器地址栏输入图片 URL、点击收藏夹、PWA 离线加载、部分 WebView 场景 -
blocked:Referer字段存在但被清空或篡改成非http:///https://开头的值,常见于企业网关、银行防火墙、隐私插件(如 uBlock Origin)、本地调试(localhost、127.0.0.1) - 漏掉
none:微信内嵌页白屏、iOS WKWebView 加载失败 - 漏掉
blocked:员工内网访问图片全 403、某些政企环境无法打开页面
return 403 比 rewrite 到默认图更可靠
用 return 403 是语义清晰、日志可查、CDN 可识别的首选;rewrite 容易埋坑:
- 原始请求带查询参数(如
/img/logo.png?v=2),rewrite默认不携带参数,导致默认图 URL 错误、返回 404 - 状态码仍是 200,监控系统无法区分“正常访问”和“盗链伪装”,日志全是成功响应
- 若默认图也在同一
location下,可能触发隐式循环匹配(除非加last或用精确location = /static/forbidden.png排除) - 真要返回图片,改用:
error_page 403 =200 /static/forbidden.png;,既保持拦截语义,又统一响应内容
secure_link 模块不是“升级版”,而是另一套逻辑
它不替代 valid_referers,而是解决不同问题:防伪造、有时效、可绑定 IP 或用户粒度。但它有硬门槛:
- 多数发行版默认不带:
nginx -V 2>&1 | grep with-http_secure_link_module无输出就得重编译或换包(如 Ubuntu 的nginx-full) - 签名逻辑必须前后端严格一致:时间戳格式、URI 路径、是否含
$remote_addr、密钥字符串,差一个字符就$secure_link = "0" - 配置必须写在具体路径的
location里(如location /dl/),且依赖 URL 中显式传参(?md5=xxx&expires=1717027200) - 它适合下载链接、后台资源分发等强管控场景,不适合全站图片自动防护
真正容易被忽略的点是:防盗链规则不是越严越好,none 和 blocked 是保底项,删了等于主动拒接一半真实用户;而 valid_referers 放错位置,等于写了等于没写——连测试都看不出问题,直到线上大量 403 报警才暴露。











