nginx secure_link模块可生成带签名和有效期的下载链接,通过$arg_st和$arg_e提取参数,用secure_link_md5基于密钥、uri和过期时间生成md5签名,由$secure_link变量返回0(通过)、1(签名错)、2(过期)、3(缺参)校验结果。

利用 Nginx 的 secure_link 模块可以生成带签名和有效期的下载链接,防止资源被未授权盗链或长期滥用。它不依赖后端程序,纯由 Nginx 在请求时校验签名与过期时间,轻量高效。
启用 secure_link 并配置基础校验
确保编译 Nginx 时已开启 --with-http_secure_link_module(主流发行版预编译包通常默认包含)。在 server 或 location 块中添加如下配置:
- 使用
secure_link $arg_st,$arg_e;提取 URL 中的签名(st)和过期时间(e)两个参数 - 用
secure_link_md5定义签名算法:格式为"$secure_link_secret$uri$arg_e",其中$secure_link_secret是服务端密钥,$uri是请求路径(不含参数),$arg_e是 Unix 时间戳 - 通过
secure_link_code判断校验结果:0表示成功,1签名错误,2已过期,3缺少参数
示例配置:
location /download/ {
secure_link $arg_st,$arg_e;
secure_link_md5 "my_secret_key$uri$arg_e";
<pre class="brush:php;toolbar:false;">if ($secure_link = "") {
return 403;
}
if ($secure_link = "0") {
# 校验通过,正常提供文件
alias /data/files/;
}
if ($secure_link = "1") {
return 403;
}
if ($secure_link = "2") {
return 410; # Gone,表示链接已过期
}}
生成合法的加密下载链接
链接格式为:https://example.com/download/file.zip?st=xxx&e=1717027200,其中:
-
e是 Unix 时间戳,代表链接过期时刻(如time() + 3600表示 1 小时后失效) -
st是对"my_secret_key/download/file.zip?e=1717027200"进行 MD5 计算后的 Base64 URL 安全编码(去掉+、/,替换=为空)
PHP 示例生成逻辑:
$secret = 'my_secret_key';
$path = '/download/file.zip';
$expires = time() + 3600;
$raw = $secret . $path . '?e=' . $expires;
$hash = base64_encode(md5($raw, true));
$hash = str_replace(['+', '/', '='], ['-', '_', ''], $hash);
$url = "https://example.com{$path}?st={$hash}&e={$expires}";Python、Node.js 等语言同理,注意使用原始二进制 MD5 输出再 Base64 编码,并做 URL 安全转换。
增强安全性与实用建议
- 密钥
$secure_link_secret应足够随机且保密,避免硬编码在配置中;可考虑通过环境变量或外部文件注入(需配合 Nginx Plus 或自定义构建) - 将
$uri替换为$request_uri可包含查询参数参与签名(如支持不同用户 ID 绑定),但需确保后端生成时也严格一致 - 配合
add_header X-Secure-Link-Status $secure_link;便于调试,生产环境建议关闭 - 不适用于高频更新或需动态权限控制的场景——此时应改用
secure_link_md5结合后端签发,或迁移到auth_request模块做细粒度鉴权
常见问题排查
返回 403 却不知原因?开启 debug 日志或临时加响应头定位:
- 检查 URL 中
st和e是否缺失或格式错误(e必须是纯数字时间戳) - 确认 Nginx 配置中
secure_link_md5的拼接字符串与生成端完全一致(空格、大小写、是否含问号等) - 验证服务器时间是否准确——过期判断依赖系统时间,偏差会导致误判
- 注意浏览器或 CDN 可能缓存 403 响应,测试时加上时间戳参数或禁用缓存










