图片、视频、下载文件被外站直接引用,会白白消耗服务器带宽,这就是典型的盗链问题。本文介绍 Nginx 防盗链配置的两种核心方案:valid_referers 校验来源与 secure_link 防盗链模块生成时效性签名 URL,包含完整配置代码、验证方法与常见问题排查,适用于静态资源密集型网站。
适用场景
- 站点图片、音视频、压缩包等静态资源频繁被第三方网站直接引用,带宽成本异常升高
- 下载站、素材站需要防止资源链接被批量转载到论坛、网盘索引站
- 通过 CDN 分发资源时,希望在源站层面前置拦截非法来源请求,降低回源流量
- 资源 URL 需要具备时效性,防止链接被无限期扩散传播
前置条件
- 一台安装 Nginx 1.10 及以上版本的服务器(secure_link 模块默认随源码编译,无需额外安装)
- 拥有站点对应的 server 配置文件编辑权限与 reload 权限
- 准备一个测试用的静态资源文件,如
/data/www/static/demo.jpg
原理说明
防盗链的本质是验证”请求是否来自授权场景”。Nginx 提供两层方案:
方案一:Referer 校验(valid_referers)。浏览器发起资源请求时会携带 Referer 头标识来源页面。Nginx 通过 valid_referers 指令声明合法来源,不在白名单内的请求变量 $invalid_referer 置为 1,配合 if 返回 403。该方案实现简单,但 Referer 可被伪造,属于基础防护。
方案二:签名 URL(secure_link)。由后端按约定算法对资源路径拼接密钥和时间戳生成 MD5 签名,客户端必须携带该签名访问。Nginx 收到请求后用同样的密钥重算并比对,签名不符或链接过期即拒绝。签名无法伪造,是严格意义上的防外链方案,适用于点播、下载等高价值资源。
操作步骤
方案一:valid_referers 配置
编辑 server 块,在静态资源 location 中添加 Referer 校验:
server {
listen 80;
server_name example.com;
location ~* \.(jpg|jpeg|png|gif|mp4|zip)$ {
valid_referers none blocked server_names
*.example.com example.com
*.baidu.com *.bing.com;
if ($invalid_referer) {
return 403;
}
root /data/www/static;
expires 7d;
}
}
参数说明:none 允许无 Referer 的请求(直接在地址栏打开、App 内嵌 WebView 常见);blocked 允许 Referer 被防火墙或代理删除的请求;server_names 允许本机 server_name;通配符 *.example.com 覆盖所有子域名。搜索引擎域名是否放行由业务决定,放行可避免搜索场景图片加载失败。
方案二:secure_link 签名配置
第一步,在 Nginx 中定义签名校验逻辑:
location /download/ {
secure_link $arg_md5,$arg_expires;
secure_link_md5 "$secure_link_expires$uri MY_SECRET_KEY";
if ($secure_link = "") {
return 403; # 签名缺失或不匹配
}
if ($secure_link = "0") {
return 410; # 签名正确但已过期
}
alias /data/www/files/;
}
第二步,由后端脚本生成签名链接。以 PHP 为例:
<?php
$secret = 'MY_SECRET_KEY';
$expires = time() + 300; // 5 分钟有效
$uri = '/download/report-2026.zip';
$md5 = base64_encode(md5($expires . $uri . $secret, true));
$md5 = strtr($md5, '+/', '-_');
$md5 = rtrim($md5, '=');
$url = $uri . '?md5=' . $md5 . '&expires=' . $expires;
echo 'https://example.com' . $url;
关键点:secure_link_md5 的字符串拼接顺序必须与生成端完全一致;签名使用 base64 URL 变体编码(-_ 替换 + /),末尾 = 去除;$uri 是解码后的请求路径,路径中含中文或空格时需确认前后端编码一致。
配置验证
方案一验证:先用 nginx -t 检查语法并 nginx -s reload 生效,然后模拟不同来源:
curl -I -H "Referer: https://evil.com/" https://example.com/demo.jpg
# 预期返回 403
curl -I https://example.com/demo.jpg
# 预期返回 200(none 放行无 Referer)
方案二验证:正确签名应返回 200;修改 md5 任意一位应返回 403;将 expires 改为过去时间戳应返回 410。可将验证命令写成脚本,放入定时任务持续监测防盗链策略是否被配置变更破坏。
常见问题
FAQ 1:开启 Referer 校验后,微信、部分 App 内打不开图片?
部分客户端发起请求时不带 Referer 头,若配置中未写 none,这类请求会被误杀。解决办法是在 valid_referers 中保留 none blocked,或改用 secure_link 方案做精确控制。
FAQ 2:secure_link 一直返回 403,如何排查?
90% 是拼接顺序或编码问题。排查顺序:确认 secure_link_md5 中变量顺序与生成端一致;确认密钥两端完全相同(注意结尾空格);确认 base64 使用了 raw 输出并做了 URL 安全替换;在 error_log 中开启 notice 级别可看到 secure_link 模块的校验过程。
总结
valid_referers 适合作为全站静态资源的第一道基础防线,配置成本低但可被伪造;secure_link 通过时效性签名实现严格的防外链控制,适合下载、点播等核心资源,两者组合使用可形成分层防护。防盗链配置上线后,建议结合访问日志持续观察误杀情况,逐步收紧白名单。