现代防盗链需摒弃单纯Referer白名单,采用Cookie(会话级)或Token(URL级)动态凭证机制;推荐Token方案,结合secure_link模块签名校验,支持时效性、路径绑定及IP/UA增强防重放。

单纯靠 Referer 白名单已无法应对现代盗链场景,尤其在 HTTPS、微信内嵌页、单页应用跳转等环境下 Referer 失效频繁。真正可靠的高级防盗链,必须结合服务端可控的动态凭证——Cookie 或 Token,让校验逻辑脱离浏览器不可信字段,转向可签名、有时效、可绑定上下文的机制。
用 Cookie 实现会话级防盗链(适合登录用户资源)
适用于会员图片、后台导出文件、个人头像等需身份关联的资源。核心是:只允许携带有效认证 Cookie 且未过期的请求访问。
- 前端登录成功后,后端 Set-Cookie 写入一个加密签名的 session_token(如 JWT 或 AES 加密的 user_id+expire_time+salt)
- Nginx 配置中用 map 指令提取并验证 Cookie 值(需配合 Lua 或 auth_request 模块做深度校验),或更轻量地:用 secure_link 模块将 Cookie 值作为密钥参与计算
- 示例简化逻辑(不依赖 Lua):
在 location 中检查 Cookie 是否存在且格式合法:if ($http_cookie !~ "session_token=[a-zA-Z0-9_\-]{32,}") { return 403; }
再配合后端签发的时效性 token(见下节),形成双重约束
用 Token 参数实现 URL 级动态防盗链(推荐主力方案)
这是生产环境最常用、最可控的方式:每个资源链接附带一次性或短时效签名 token,服务端与 Nginx 共享密钥,独立完成校验,无需回源。
- Token 必须包含三要素:资源路径($uri)、时间戳(t=1724200320)、过期时长(e=300),全部参与签名
- 使用 secure_link + secure_link_md5 指令,例如:
secure_link $arg_t,$arg_e;secure_link_md5 "$uri$arg_t$arg_e$secret_key";
其中 $secret_key 应为动态派生值(如按用户 ID 哈希),而非全局固定字符串 - 客户端生成链接示例:
/images/photo.jpg?t=1724200320&e=300&md5=abc123...
Nginx 自动比对 md5 值,匹配则放行;不匹配或过期(t+e < now)则设 $secure_link = "",触发 return
混合策略:Token + IP/User-Agent 绑定(防重放)
签名 token 可被截获重放,尤其在公共 WiFi 下。增强手段不是加复杂度,而是收紧上下文范围:
- 在 secure_link_md5 表达式中加入客户端特征,如:
secure_link_md5 "$uri$arg_t$arg_e$remote_addr$user_agent$secret_key";
注意:user_agent 易伪造,仅作辅助;IP 更可靠,但需考虑 CDN 回源真实 IP(用 $http_x_forwarded_for 并校验可信代理) - 对高敏感资源(如付费视频片段),可要求 token 由后端接口实时签发,并记录签发指纹(IP+UA+时间),Nginx 层通过 auth_request 转发校验请求到内部 API
- 避免在日志中明文记录完整 token(用 log_format 过滤 $args 或只记 $uri)
关键注意事项与避坑点
- 不要写 secure_link_magic_token —— 官方模块无此指令,Nginx 启动直接报错 “unknown directive”
- HTTPS 下 Referer 不可靠,valid_referers 必须含 none 和 blocked,Token 方案正好弥补这一断层
- token 过期时间建议控制在 120–300 秒,兼顾安全与用户体验;长期有效的 token 本质等于裸奔
- 返回响应别只用 return 403,可配 error_page 指向一张 1×1 透明 GIF,既隐藏防护痕迹,又节省带宽


















