网站图片被外站盗链怎么办:Nginx防盗链配置与误伤排查

    发布时间:2026-09-17 12:32 更新时间:2026-09-17 12:32 阅读量:0

    做图片站或者内容站的朋友,多少都遇到过这种情况:服务器带宽莫名上涨,访问日志里一堆来自陌生域名的图片请求,点进去看,别人站点上挂的正是你辛苦拍的图、做的图。这就是典型的图片盗链——对方只写了一个图片地址,流量和带宽却全部由你承担。要挡住它,最直接的办法是在 Nginx 层做 Referer 校验,也就是常说的防盗链。

    不过防盗链是把双刃剑,配得太严,自己站内的图片先打不开,搜索引擎抓不到图,CDN 回源也会失败。下面从原理讲到配置,再到误伤排查,尽量让你一次配对。

    Referer 校验是怎么工作的

    浏览器请求图片时,一般会在请求头里带上 Referer,标明自己是从哪个页面跳过来的。Nginx 的 ngx_http_referer_module 模块可以读取这个头,用 valid_referers 指令列出白名单。命中白名单就正常返回图片,没命中就把 $invalid_referer 置为 1,我们在配置里根据这个变量返回 403 或者一张占位图。

    需要先明确一点:Referer 是客户端自愿发送的,可以被伪造,也可以被浏览器或代理策略去掉。所以防盗链不是安全机制,它只能拦住普通站长的顺手盗链,拦不住刻意抓取。真正要防批量抓取,还得靠限速、签名 URL 或者图片加水印,具体以实际业务需求为准。

    另外,同一个站点内部的跳转也可能出现 Referer 与主域名不一致的情况,比如用了 www 与裸域两套域名,或者主站和图片站分离,这些都要提前想到,否则就会误伤自己。

    valid_referers 的正确写法

    先看一段可以直接落地的配置。假设图片目录是 /www/site/static/img/,主域名是 example.com,同时使用了 CDN:

    location ~* \.(gif|jpg|jpeg|png|webp|bmp|svg)$ {
        valid_referers none blocked
                       server_names
                       *.example.com example.com
                       *.baidu.com *.google.com *.bing.com *.sogou.com *.so.com *.sm.cn
                       *.example.com.cdn.example.net;
    
        if ($invalid_referer) {
            return 403;
        }
    
        expires 30d;
        add_header Cache-Control "public";
        access_log off;
    }

    逐段说明几个关键点。none 表示允许 Referer 为空的请求,这是必须留的:用户直接在地址栏打开图片、从收藏夹进入、部分浏览器在 HTTPS 页面引用 HTTP 图片时都会不带 Referer,封掉它等于封掉正常访问。blocked 表示允许 Referer 存在但被防火墙或代理抹掉内容的请求,同样建议放行。

    server_names 会让 Nginx 自动把你所有 server_name 里配置过的域名加入白名单,这是最省事的站内放行方式。如果你有多个域名或子域名,再补上 *.example.com 这样的通配写法。注意 valid_referers 里的域名支持通配符 *,但只能放在域名开头,写成 *.example.com 是合法且常用的。

    搜索引擎蜘蛛要不要放行,取决于你的 SEO 策略。放行百度、Google、Bing 等常见蜘蛛,可以让图片搜索带来额外流量,代价是这些流量同样消耗带宽;如果图片是核心付费资源,也可以不放。上面的写法属于比较宽松的常见做法,具体放哪些蜘蛛请结合自己的实际情况调整。

    还要注意 CDN 域名。开了 CDN 之后,浏览器请求的是 CDN 地址,回源时 CDN 节点发出的请求 Referer 可能是空的,也可能是 CDN 自己的域名。如果配置里只写了源站域名,回源就会被 403 掉,表现为图片在 CDN 上大面积不可用。稳妥做法是把 CDN 回源域名也加进白名单,或者在 CDN 侧配置回源时移除或改写 Referer,具体以所用 CDN 厂商的文档为准。

    如果不想直接返回 403,可以换成一张占位图,观感上更友好一些:

    if ($invalid_referer) {
        rewrite ^/ /static/img/anti-leech.png break;
    }

    误伤排查与常见坑

    配置改完别急着全量上线,先按下面的顺序自查。第一步,用 curl 模拟带 Referer 和不带 Referer 两种请求,看返回码是否符合预期:

    # 不带 Referer,应返回 200
    curl -I https://www.example.com/static/img/test.jpg
    
    

    带站外 Referer,应返回 403

    curl -I -e "https://other-site.com/" https://www.example.com/static/img/test.jpg

    带站内 Referer,应返回 200

    curl -I -e "https://www.example.com/post/1.html" https://www.example.com/static/img/test.jpg

    如果站内请求返回 403,先看 Referer 里的域名是否和 server_names 完全对得上,包括有没有带 www、有没有多余端口。第二步,检查 location 的匹配范围,正则 ~* 是大小写不敏感匹配,别把 CSS、JS 也误圈进来,否则页面样式错乱比图片挂掉更难排查。第三步,确认 HTTPS 与 HTTP 混用的情况:HTTPS 页面引用 HTTP 图片时,浏览器可能不发 Referer,这也是必须保留 none 的原因之一。

    还有一个容易被忽略的点是多域名与跨域。主站、图片站、移动站如果分散在不同域名,白名单里要全部列出;用 add_header Referrer-Policy 之类策略把 Referer 裁成只带域名(origin)时,白名单里的完整域名写法依然能匹配,但如果你写的是带路径的规则就会失效——valid_referers 只按域名匹配,不按路径匹配。

    排查时最有用的是日志。可以在 location 里临时加上 add_header X-Ref "$http_referer";,用浏览器开发者工具看响应头,或者在 403 返回时单独记一个日志:

    if ($invalid_referer) {
        access_log /www/wwwlogs/anti-leech.log;
        return 403;
    }

    观察几天这个日志,里面出现的域名基本就是盗链方。如果发现误封了正常来源,把它补进白名单再重载 Nginx 即可。改完配置记得先 nginx -t 校验语法,再 nginx -s reload 平滑生效。

    小结

    防盗链的核心是三件事:放行空 Referer 与 blocked,别把自己人挡在门外;把站内所有域名和 CDN 回源域名写进白名单;上线前用 curl 和日志各验证一遍。Referer 校验只能解决普通盗链,遇到持续抓取还要配合限速、图片水印和访问日志分析。如果你的站点已经用了 CDN,建议同时检查一遍 CDN 侧是否支持 Referer 黑白名单,把校验放在离用户更近的节点上,既能省源站带宽,也避免回源被拦导致的大面积图片异常。

    继续阅读

    📑 📅
    宝塔面板 Nginx 与 Apache 该选哪个:并发模型差异与切换后伪静态失效处理 2026-09-17
    Nginx gzip 与 Brotli 压缩怎么开:级别、预压缩与不生效排查 2026-09-17
    同一台服务器跑多个网站:Nginx server_name 匹配顺序与默认站点防串站配置 2026-09-17
    WordPress图片站提速:WebP批量转换、懒加载与Nginx静态直返 2026-09-17
    网站被恶意刷流量刷接口怎么办:Nginx限速与IP封禁配置思路 2026-09-17
    WordPress后台打开极慢前台正常:插件钩子与admin-ajax排查 2026-09-17
    WordPress定时发布失效排查:wp-cron不触发与服务器计划任务替代方案 2026-09-18
    301跳转链太长拖慢首屏:curl与浏览器面板揪出重定向链 2026-09-18
    宝塔面板数据库连不上排查:socket与3306端口、bind-address区别 2026-09-18
    Nginx上传目录禁止执行PHP:location匹配与fastcgi拦截写法 2026-09-18