Nginx 如何配置防盗链(Hotlinking Prevention)?
在 Nginx 中配置防盗链(Hotlinking Prevention)的核心原理是利用 HTTP 请求头中的 Referer 字段。Referer 记录了用户是从哪个网页跳转或请求该资源的。
Nginx 提供了 ngx_http_referer_module 模块,通过 valid_referers 指令和 $invalid_referer 变量,可以非常方便地实现白名单或黑名单机制。
以下是详细的配置指南:
1. 基础防盗链配置(白名单模式)
这是最常用的配置方式。只允许指定的域名(以及直接访问)来获取你的图片、视频等静态资源。
打开你的 Nginx 配置文件(通常是 /etc/nginx/nginx.conf 或 /etc/nginx/conf.d/你的域名.conf),在相应的 server 块中添加或修改 location 块:
server {
listen 80;
server_name example.com www.example.com;
# 匹配需要防盗链的文件类型
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf|flv|mp4|ico|webp)$ {
# 定义合法的 Referer 来源
valid_referers none blocked server_names *.example.com example.com ~\.google\. ~\.baidu\.;
# 如果来源不合法(即不在上面的列表中),$invalid_referer 变量的值会变为 1
if ($invalid_referer) {
return 403; # 返回 403 Forbidden 错误
}
# 静态资源的其他配置,如缓存时间
expires 30d;
access_log off;
}
}
参数详解:
location ~ .*\.(...):使用正则表达式匹配需要保护的文件后缀名。valid_referers:定义合法的来源,参数说明如下:none:允许没有Referer头的请求。这意味着允许用户直接在浏览器地址栏输入图片地址访问。(建议开启,否则自己直接访问也会报错)blocked:允许Referer头存在,但其值被防火墙或代理服务器修改或隐藏的情况(通常不以http://或https://开头)。server_names:允许当前 Nginx 配置中server_name指令定义的域名。*.example.com example.com:直接指定允许的域名,支持通配符*。~\.google\. ~\.baidu\.:支持正则表达式(以~开头),这里表示允许谷歌和百度的图片搜索抓取。
$invalid_referer:如果请求的Referer与valid_referers列表中不匹配,这个变量的值就会是1,从而触发if语句。
2. 高级配置:返回一张“防盗链提示”图片
如果你不想直接返回冷冰冰的 403 错误,可以利用 rewrite 将盗链请求重定向到一张提示图片(例如写着“仅限 example.com 访问”的图片)。
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf|flv|mp4|ico|webp)$ {
valid_referers none blocked server_names *.example.com example.com;
if ($invalid_referer) {
# 将非法请求重定向到指定的防盗链提示图片
rewrite ^/ http://www.example.com/images/no-leech.png;
}
}
⚠️ 严重警告(死循环风险):
如果你使用重定向提示图片,请确保这张提示图片不在防盗链的拦截范围内!
解决方法有两种:
- 把提示图片放在另一个没有防盗链的域名下。
- 将提示图片排除在拦截规则之外,例如:plaintext
location ~ .*\.(gif|jpg|jpeg|png)$ { # 排除 no-leech.png 文件 if ($request_uri ~* "no-leech.png") { break; } valid_referers none blocked server_names example.com; if ($invalid_referer) { rewrite ^/ http://www.example.com/images/no-leech.png; } }
3. 黑名单模式(阻止特定域名)
如果你只想拦截某几个一直盗用你资源的恶意网站,允许其他所有网站,可以使用黑名单机制。由于 valid_referers 主要是做白名单的,做黑名单可以直接匹配 $http_referer 变量。
location ~ .*\.(gif|jpg|jpeg|png|bmp)$ {
# 检查 Referer 中是否包含恶意域名
if ($http_referer ~* (badsite\.com|evil\.org|thief\.net)) {
return 403;
}
}
4. 使配置生效并测试
修改完配置文件后,请务必检查语法并重载 Nginx:
# 测试配置文件语法是否正确
nginx -t
# 重新加载 Nginx 配置
nginx -s reload
# 或者
systemctl reload nginx
如何测试防盗链是否生效?
你可以使用 curl 命令行工具来模拟伪造的 Referer 进行测试:
测试合法来源(模拟从你的网站访问):
bashcurl -I -e "http://www.example.com" http://www.example.com/test.jpg预期结果:返回
HTTP/1.1 200 OK测试非法来源(模拟从别人网站盗链):
bashcurl -I -e "http://www.badsite.com" http://www.example.com/test.jpg预期结果:返回
HTTP/1.1 403 Forbidden(或者 302 重定向到提示图片)测试无 Referer(直接访问):
bashcurl -I http://www.example.com/test.jpg预期结果:如果在
valid_referers中加了none,应返回200 OK。
💡 补充说明与局限性
- 无法防住专业爬虫:基于
Referer的防盗链是防君子不防小人的。HTTP 头是由客户端发送的,使用curl、Python 脚本或专门的采集软件可以轻易伪造Referer字段绕过这个限制。 - 如何防伪造? 如果你需要更高强度的防盗链(如视频网站付费内容),需要结合 URL 签名(动态 Token 防盗链)。这需要你的后端程序生成带有过期时间和签名的 URL,Nginx 配合
Secure Link模块(ngx_http_secure_link_module)来校验,这种方式是无法伪造的。