基于时间戳的防盗链校验需在Nginx中结合map、if及secure_link或Lua实现:先用map校验t参数格式与时效性,再通过密钥+URI+t生成HMAC-SHA256签名(推荐Lua)或MD5(secure_link模块)比对,确保时间戳未篡改且签名绑定路径,防止重放与复用。

要实现基于时间戳的防盗链校验,核心是在 Nginx 的 location 块中结合 map、if 和内置变量(如 $arg_t、$time_iso8601)完成签名验证与时效判断。这不是单纯靠 valid_referers 能解决的,需手动校验 URL 中的时间戳和签名是否合法且未过期。
定义时间戳与签名规则
约定资源 URL 格式为:https://example.com/static/img.jpg?t=1717027200&sign=abc123
其中:
- t 是 Unix 时间戳(秒级),表示该链接的有效截止时间;
- sign 是服务端用密钥对 URI + t 等字段生成的 HMAC-SHA256 签名(Base64 或 hex 编码)。
注意:签名必须包含时间戳,防止篡改;同时建议加入文件路径(如 $uri)避免签名复用到其他资源。
在 http 块中预定义 map 映射做基础校验
利用 map 提前解析并判断时间戳有效性,避免在每个请求中重复计算:
(放在 nginx.conf 的 http {} 块内)
map $arg_t $is_expired {
default 1;
"" 1;
~^[0-9]{10}$ 0;
}
<p>map $arg_t $is_valid_time {
default 0;
~^[0-9]{10}$ "$arg_t > $time_unix";
}
</p>
说明:
- 第一个 map 检查 t 是否为 10 位纯数字(Unix 时间戳格式);
- 第二个 map 判断时间戳是否已过期($time_unix 是 Nginx 内置秒级时间变量)。
在 location 块中组合校验逻辑
以静态资源目录为例,在 server 或 location 中写入完整控制逻辑:
location ^~ /static/ {
# 允许直接访问(如内部系统调用)或带合法签名的请求
if ($is_expired) { return 403; }
if ($is_valid_time = 0) { return 403; }
<pre class="brush:php;toolbar:false;"># 校验签名:使用 secure_link 模块(推荐)或自定义 Lua(OpenResty)
# 方式一:用 Nginx 官方 secure_link(需编译时启用 --with-http_secure_link_module)
secure_link $arg_sign,$arg_t;
secure_link_md5 "your_secret_key$uri$arg_t";
if ($secure_link = "") { return 403; }
if ($secure_link = "0") { return 403; }
# 验证通过,正常提供文件
alias /var/www/static/;
expires 1h;
}
说明:
- secure_link 指令将签名和时间戳传入;
- secure_link_md5 指定服务端拼接密钥+路径+t 后计算的 MD5(注意:实际应使用更安全的 SHA256,但原生模块仅支持 MD5;如需 SHA256,建议用 OpenResty + Lua);
- $secure_link = "" 表示参数缺失或格式错误;= "0" 表示签名不匹配。
替代方案:用 OpenResty + Lua 实现灵活校验
若需 SHA256、动态密钥或更复杂逻辑(如绑定用户 ID),推荐用 Lua:
location ^~ /static/ {
access_by_lua_block {
local args = ngx.req.get_uri_args()
local t = args["t"]
local sign = args["sign"]
<pre class="brush:php;toolbar:false;"> if not t or not sign or not string.match(t, "^%d+$") then
ngx.exit(403)
end
local expire = tonumber(t)
if ngx.time() > expire then
ngx.exit(403)
end
local expected = ngx.sha256_hex("my_secret" .. ngx.var.uri .. t)
if sign ~= expected then
ngx.exit(403)
end
}
alias /var/www/static/;
expires 1h;
}
优点:签名算法可控、可加盐、可集成用户上下文;缺点:需部署 OpenResty 并启用 Lua 支持。
关键是把时间约束和密码学校验耦合在同一个校验流程里,确保攻击者既不能伪造时间戳,也不能绕过签名重放旧链接。不复杂但容易忽略细节——比如没校验 t 的格式导致整数溢出绕过,或签名未绑定 URI 导致链接被挪用到其他文件。










