Nginx 防盗链与 referer 校验的局限
发布时间:2025-11-29 19:54       
更新时间:2025-11-30 12:02
自己网站的图片被别的页面直接外链,流量账单算在你头上,这是防盗链要解的问题。Nginx 里最常见的实现是 referer 校验,但它有先天局限,这篇把写法和局限一起说透。
一、valid_referers 写法
```
location ~* \.(jpg|png|gif|webp)$ {
valid_referers none blocked server_names
*.example.com example.com;
if ($invalid_referer) {
return 403;
}
root /data/www/images;
}
```
取值含义:none 是地址栏直接打开(请求不带 referer 头);blocked 是有头但内容被代理抹掉;server_names 匹配本机的 server_name;后面是白名单域名,也可以用 ~ 开头的正则。落在白名单之外,$invalid_referer 即为真,返回 403。if 加 return 是 Nginx 里少数安全可靠的组合,可以放心用。$invalid_referer 是个独立变量,日志里看不到它的值,验证规则时用带与不带 referer 的 curl 各请求一次,对照结果最直观。
二、为什么说它不可靠
referer 是浏览器生成的请求头,服务端完全无法验证真伪:
- 伪造 referer 只要一行:curl -e "https://example.com/" -O 图片地址。
- 浏览器出于隐私默认收窄 Referrer-Policy,正常用户也可能带不上 referer,白名单反而误伤自己人。
- 各类客户端内嵌 webview 的 referer 行为五花八门,规则越严误伤越多。
结论:referer 校验只能挡成本最低的外链,是礼貌性防线,不是安全边界。它防的是流量盗用,不是版权复制——截图、另存为永远防不住,两层问题要分开看。白名单还有维护成本,合作方域名经常变动,每季度对一遍清单,失效条目及时清理,否则规则越积越乱。
三、更可靠的补充:签名 URL
思路是给链接加时效与校验参数,Nginx 用 secure_link 模块实现:
```
location /files/ {
secure_link $arg_md5,$arg_expires;
secure_link_md5 "$secure_link_expires$uri 你的密钥";
if ($secure_link = "") { return 403; }
if ($secure_link = "0") { return 410; }
}
```
服务端用约定密钥算出 md5 与过期时间拼进 URL,链接到期或参数被篡改即失效。防遍历、防盗链都靠得住,代价是业务代码要配合生成签名。
四、落地建议
公开图片资源,referer 校验加放行空 referer 即可,别追求铁桶;真正需要保护的下载与视频资源,直接上签名 URL,必要时配合 limit_conn 与 limit_rate 控制并发和速度。把防盗链当作成本控制手段而不是安全手段,预期就摆正了。