基于本文回答

播面 播面

刷题像听歌,多听自然懂
0
评论

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 块:

plaintext
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:如果请求的 Referervalid_referers 列表中不匹配,这个变量的值就会是 1,从而触发 if 语句。

2. 高级配置:返回一张“防盗链提示”图片

如果你不想直接返回冷冰冰的 403 错误,可以利用 rewrite 将盗链请求重定向到一张提示图片(例如写着“仅限 example.com 访问”的图片)。

plaintext
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;
    }
}

⚠️ 严重警告(死循环风险)
如果你使用重定向提示图片,请确保这张提示图片不在防盗链的拦截范围内
解决方法有两种:

  1. 把提示图片放在另一个没有防盗链的域名下。
  2. 将提示图片排除在拦截规则之外,例如:
    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 变量。

plaintext
location ~ .*\.(gif|jpg|jpeg|png|bmp)$ {
    # 检查 Referer 中是否包含恶意域名
    if ($http_referer ~* (badsite\.com|evil\.org|thief\.net)) {
        return 403;
    }
}

4. 使配置生效并测试

修改完配置文件后,请务必检查语法并重载 Nginx:

bash
# 测试配置文件语法是否正确
nginx -t

# 重新加载 Nginx 配置
nginx -s reload
# 或者
systemctl reload nginx

如何测试防盗链是否生效?

你可以使用 curl 命令行工具来模拟伪造的 Referer 进行测试:

  1. 测试合法来源(模拟从你的网站访问):

    bash
    curl -I -e "http://www.example.com" http://www.example.com/test.jpg

    预期结果:返回 HTTP/1.1 200 OK

  2. 测试非法来源(模拟从别人网站盗链):

    bash
    curl -I -e "http://www.badsite.com" http://www.example.com/test.jpg

    预期结果:返回 HTTP/1.1 403 Forbidden(或者 302 重定向到提示图片)

  3. 测试无 Referer(直接访问):

    bash
    curl -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)来校验,这种方式是无法伪造的。
00:00
00:00