nginx 防盗链需分层协作:referer 校验由 nginx 快速初筛非法来源,token 签名验证则交由后端完成,nginx 仅做参数存在性与格式粗筛,不参与密钥管理或 hmac 运算。

Nginx 本身不支持动态生成或验签 Token(如 HMAC-SHA256),它无法解析复杂签名逻辑或访问后端密钥。所谓“结合 Token 签名的动态防盗链”,本质是 Nginx 做前置校验 + 后端服务生成/验证 Token,Nginx 只负责按规则拦截明显非法请求,把签名验证交给更可控的业务层。Referer 可伪造,Token 才真正防篡改——两者不是并列配置,而是分层协作。
下面讲清楚怎么落地:
Nginx 配合 Token 的防盗链分工逻辑
- Referer 校验(Nginx 做):快速筛掉无 Referer、来源域名明显非法(如
evil.com)的请求,降低后端压力。 - Token 校验(后端做):对每个资源 URL 附加时间戳+签名(如
/img/logo.png?t=1722250800&sign=abc123),后端验证时效性、签名合法性。 - Nginx 不参与 sign 计算,但可配合做基础路由和透传,甚至用
map或rewrite提前拒绝明显过期或缺失参数的请求(轻量级兜底)。
在 Nginx 中实现 Token + Referer 协同防护
你可以在 location 块里同时检查 Referer 和 URL 参数,做到“双因子初筛”:
Token 消耗追踪工具。当用户需要监控 API token 使用情况、生成每日/每周消耗报告、分析使用趋势时使用此 Skill。功能包括:自动记录每次对话的 token 消耗、生成数据表格报告、计算使用趋势和预测、支持定时推送日报。
location ~* \.(jpg|jpeg|png|gif|webp|mp4)$ {
# Step 1:Referer 白名单(允许自身域名、空 Referer、合作域名)
valid_referers none blocked example.com *.example.com partner-site.com;
if ($invalid_referer) {
return 403;
}
# Step 2:强制要求 t(时间戳)和 sign(签名)两个参数存在
if ($args !~ "^t=[0-9]+&sign=[a-zA-Z0-9_\-]{16,64}$") {
return 403;
}
# Step 3(可选):简单时效校验(Nginx 能做,但精度有限)
set $ts $arg_t;
if ($ts = "") { return 403; }
if ($ts "1722254400") { return 403; } # 示例:拒绝晚于 2026-07-29 20:00 的请求(有效期2小时)
# 正常代理到后端,由后端完成最终 sign 验证
proxy_pass http://backend;
}
⚠️ 注意:Nginx 的
$arg_t是字符串,不能直接做数学比较(如$ts + 3600 不可行)。上面的时间范围硬编码仅作示意;真实场景建议把时效判断完全交给后端,Nginx 只做“参数存在性”和“格式粗筛”。
后端生成 Token 的关键要点(供你对接参考)
- 签名原文示例:
/img/photo.jpg|1722250800|salt_key(资源路径 + 时间戳 + 固定密钥) - 使用 HMAC-SHA256 生成 sign,并 base64url 编码或 hex 输出
- 时间戳单位为秒,允许 5 分钟左右时钟偏差(需后端统一 NTP)
- 签名 URL 示例:
https://example.com/img/photo.jpg?t=1722250800&sign=9f8e7d6c5b4a3928
为什么不能只靠 Nginx 做 Token 验签?
- Nginx 没有内置 HMAC 函数(OpenResty 的
resty.hmac可用,但标准版 Nginx 不支持) - 密钥必须安全存储,Nginx 配置文件不适合放密钥(易泄露)
- 签名算法升级(如换 SHA512)、密钥轮换、黑名单失效等逻辑,必须由应用层统一管理
所以真正的动态防盗链,是:
- 前端链接由后端模板或 JS SDK 动态拼出带 sign 的 URL
- Nginx 拦截无参、格式错、Referer 异常的请求
- 后端收到请求后,提取
t和sign,校验时间窗口 + 重算签名比对
不复杂但容易忽略。










