secure_link比referer更防伪造,因referer可被客户端随意篡改,仅能拦截懒盗链;而secure_link要求url携带服务端生成的md5签名,绑定路径、时间戳及ip等要素,验证失败即返回403,无法伪造或推导。

用 secure_link 实现高级防盗链签名,核心是把“谁、什么时候、要什么”这三个要素绑定进 URL,并由 Nginx 在请求时原地校验,不依赖 Referer 头,也无需后端参与。它比传统 referer 防盗链更可靠,因为签名无法被客户端伪造。
为什么 secure_link 比 referer 更防伪造
Referer 可被浏览器或工具随意修改,只能拦住“懒盗链”;而 secure_link 要求每个链接都带服务端生成的 MD5 签名,且签名必须包含路径、时间戳(可选 IP),验证失败直接 403。攻击者即使拿到一个有效链接,也无法推导出其他文件的签名逻辑,更不能延长有效期。
关键配置三步走
在对应 location 块中完成以下配置:
-
提取参数:用
secure_link $arg_st,$arg_e;从 URL 中取签名(st)和过期时间(e)。参数名可自定义,但前后端必须一致 -
定义签名规则:用
secure_link_md5 "your_secret_key$uri$arg_e$remote_addr";明确拼接顺序。注意:$uri带前导斜杠(如/dl/report.pdf),$arg_e是秒级 Unix 时间戳,$remote_addr若经 CDN 需先配set_real_ip_from+real_ip_header X-Forwarded-For -
拦截非法请求:
if ($secure_link = "") { return 403; } if ($secure_link = "0") { return 410; }成功时变量值为"1",可继续走alias或root
生成合法链接要注意的细节
服务端生成 URL 时,必须严格复刻 Nginx 的拼接逻辑:
- 例如 Nginx 配置为
secure_link_md5 "abc123$uri$arg_e$remote_addr",那么 Python 里就要写:h = md5(f"abc123{/dl/file.zip}1735689600{client_ip}".encode()).hexdigest() - 密钥建议 ≥32 字符,避免硬编码,可通过环境变量注入
- 时间戳用
int(time.time()) + 1800这类方式生成,单位是秒,不是毫秒 - 最终链接形如:
https://example.com/dl/file.zip?st=7a8b9c...&e=1735689600
增强安全性的实用建议
单纯绑定路径+时间还不够强,可叠加以下策略:
-
绑定客户端真实 IP:加入
$remote_addr后,同一链接在不同设备上会失效,防止分享扩散 -
限制访问路径为 internal:在 location 中加
internal;,禁止用户直接请求/dl/xxx,只允许通过带签名的跳转访问 -
搭配安全响应头:加
add_header Content-Disposition "attachment";强制下载,避免浏览器直接渲染敏感文件 - 密钥轮换机制:定期更新密钥并重发新链接,旧链接自动全部失效
不复杂但容易忽略的是:前后端拼接字符串的顺序、空格、大小写、是否含查询参数,必须完全一致,否则签名永远对不上。











