扫码加入

  • 正文
  • 相关推荐
申请入驻 产业图谱

Nginx | secure_link 模块,筑起资源链接签名防线,防盗链终极方案

2025/10/15
2063
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

大家好,我是 WeiyiGeek,一名深耕安全运维开发(SecOpsDev)领域的技术从业者,致力于探索DevOps与安全的融合(DevSecOps),自动化运维工具开发与实践,企业网络安全防护,欢迎各位道友一起学习交流、一起进步 ,若此文对你有帮助,一定记得倒点个关注⭐与小红星❤️,收藏学习不迷路  。

使用 secure_link 模块实现进阶资源防盗链

描述: 前面我们说到通过 Referer 模块根据 referer 请求头来判断请求来源是否合法,由于 Referer 请求头可以被伪造,所以我们需要一种更加安全的方式来验证资源的访问权限,即通过在 URL 中嵌入签名的方式来验证请求的合法性,例如,通过 secure_link 模块来实现。

secure_link 模块通过接收在 URL 中嵌入一个签名 URL(通常由后端程序生成,例如 java),然后服务器端根据这个签名来验证请求的合法性。这种方式相比于 Referer 头更加安全可靠,因为它不依赖于客户端的设置,而是直接由服务端控制。值得注意的是,secure_link 模块默认并未编译进 Nginx 中,可通过 --with-http_secure_link_module 参数启用。

在配置了 secure_link 模块后,我们可以使用 secure_link 和 secure_link_md5 指令来定义一个表达式,该表达式将用于生成签名,或者通过使用 secure_link_secret 指令来指定一个密钥仅对 URL 进行哈希的简单办法,其原始字符串通常由以下几个部分组成:

    资源位置:例如,一个文件的路径或一个资源的标识符客户信息:例如,用户的 ID 、IP 地址或其他标识符时间戳:一个用于验证请求是否在有效时间内的数字或字符串密钥:一个用于生成签名的秘密字符串,仅服务端

温馨提示:若文章代码块中存在乱码,请通过文末的阅读原文链接,在知识星球中阅读,或者直接访问原文链接:https://articles.zsxq.com/id_rx229kjix356.html

指令参数

# 定义一个包含变量的字符串,将从该字符串中提取链接的校验和值和生存期。
Syntax:  secure_link expression;
Default:  —
Context:  http, server, location

# 定义一个表达式,将计算该表达式的MD5哈希值并将其与请求中传递的值进行比较。
Syntax:  secure_link_md5 expression;
Default:  —
Context:  http, server, location

# 定义用于检查所请求链接的真实性的密钥。
Syntax:  secure_link_secret word;
Default:  —
Context:  location

温馨提示:$secure_link 变量可用于判断请求是否合法,其值为 "1" 表示链接有效,"0" 或空表示无效。

示例演示

示例 1.使用 secure_link 和 secure_link_md5 指令来验证请求的合法性。

假设,我们希望通过 URL 传递一个签名来验证请求下载的合法性,例如:原请求为 /secure_link/test.txt?md5=base64编码后的MD5&expires=过期时间戳,其中 md5 为原始字符串的 MD5 哈希值的 base64 编码值,expires 为一个时间戳。

首先,我们在服务端按照一定规则生成 md5 哈希值,例如:过期时间戳URL客户端标识 密钥,这里客户端标识使用客户端 IP,secret 密钥为固定的 WeiyiGeek,则在服务端生成签名代码如下:

echo -n '2147483647/secure_link/test.txt10.20.172.214 WeiyiGeek' | openssl md5 -binary | openssl base64 | tr +/ -_ | tr -d =
cjzz0IE4D-5QhyfJwa_moQ

其次,我们在 Nginx 配置文件中使用 secure_link 和 secure_link_md5 指令来验证请求的合法性,配置如下修改完毕后请重新加载 Nginx 配置。

location /secure_link/ {
  # 定义一个包含变量的字符串,将从该字符串中提取链接的校验和值和生存期。
  secure_link $arg_md5,$arg_expires;
# 定义一个表达式,将计算该表达式的MD5哈希值并将其与请求中传递的值进行比较。
  secure_link_md5 "$secure_link_expires$uri$remote_addr WeiyiGeek";

if ($secure_link = "") {
    # 如果链接无效,则返回403状态码。
    return 403;
  }

if ($secure_link = "0") {
   # 如果链接过期,则返回410状态码。
    return 410;
  }

# 如果链接有效,则返回200状态码。
return 200 'valid secure link:$secure_link, expires: $secure_link_expires';
}

然后,我们使用 curl 命令测试不同请求 URL 参数的结果:

# 指定一个错误的md5值无效链接,返回 403 状态码
$ curl 'http://test.weiyigeek.top/secure_link/test.txt?md5=rYWl3gNgVRpSWahUG5qkgA&expires=2147483647'

<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.29.0</center>
</body>
</html>

# 指定一个正确的md5值,但是过期时间为当前时间戳,返回 410 状态码
TIMESTAMP=$(date +"%s")
MD5=$(echo -n "${TIMESTAMP}/secure_link/test.txt10.20.172.214 WeiyiGeek" | openssl md5 -binary | openssl base64 | tr +/ -_ | tr -d =)
$ curl "http://test.weiyigeek.top/secure_link/test.txt?md5=${MD5}&expires=${TIMESTAMP}"

<html>
<head><title>410 Gone</title></head>
<body>
<center><h1>410 Gone</h1></center>
<hr><center>nginx/1.29.0</center>
</body>
</html>

# 指定一个正确的md5值,且过期时间未过期的链接,返回 200 状态码并显示有效信息
$ curl 'http://test.weiyigeek.top/secure_link/test.txt?md5=cjzz0IE4D-5QhyfJwa_moQ&expires=2147483647'
valid secure link:1, expires: 2147483647, secure_link_md5: cjzz0IE4D-5QhyfJwa_moQ

weiyigeek.top-示例1防盗链实践结果图

示例 2.使用 secure_link_secret 指令来配置密钥,将请求的 URL 分为三个部分 /prefix/hash/link,其中 prefix 为固定的前缀,hash 为原始字符串的 MD5 哈希值,link 为原始链接,针对 "link 密钥" 做 md5 哈希值"

首先,生成一个测试文件 test.txt 到 /usr/local/nginx/html/ 目录中

echo "valid secure with secure_link_secret" > /usr/local/nginx/html/test.txt

其次,在 Nginx 配置文件中添加如下 location 配置,并重新加载 Nginx 配置。

location /secure_link_secret/ {
  # 定义一个密钥,用于生成和验证链接的哈希值。
  secure_link_secret WeiyiGeek;

# 若链接无效,则返回403状态码。
if ($secure_link = "") {
      return 403;
  }

# 否则,重定向到原始链接。
  rewrite ^ /secure/$secure_link;
}

location /secure/ {
alias /usr/local/nginx/html/; # 定义原始链接的路径。
  internal;  # 内部重定向,不对外暴露此location的访问路径。
}

然后,生成一个签名链接,例如:访问 text.txt 文件

# 生成签名
echo -n 'test.txtWeiyiGeek' | openssl md5 -hex
5c0bc83889a4704c7c6c727ea92358de

# 拼接签名链接 URL
/secure_link_secret/5c0bc83889a4704c7c6c727ea92358de/test.txt

最后,使用 curl 命令测试请求生成的签名链接,查看效果。

# 若指定的MD5值无效,返回 403 状态码
$ curl http://test.weiyigeek.top/secure_link_secret/3f99ad0f4a6d490d71fe3c1f62915dea/test.txt

# 若指定的MD5值有效,但是文件名称不存在,同样返回 403 状态码
$ curl http://test.weiyigeek.top/secure_link_secret/5c0bc83889a4704c7c6c727ea92358de/notfound.txt

# 若指定的签名链接有效,则返回 200 状态码并显示文件内容
$ curl http://test.weiyigeek.top/secure_link_secret/5c0bc83889a4704c7c6c727ea92358de/test.txt
valid secure with secure_link_secret

weiyigeek.top-示例2防盗链实践结果图

官方文档:https://nginx.org/en/docs/http/ngx_http_secure_link_module.html

 

加入:作者【全栈工程师修炼指南】知识星球

『 全栈工程师修炼指南』星球,主要涉及全栈工程师(Full Stack Development)实践文章,包括但不限于企业SecDevOps和网络安全等保合规、安全渗透测试、编程开发、云原生(Cloud Native)、物联网工业控制(IOT)、人工智能Ai,从业书籍笔记,人生职场认识等方面资料或文章。

相关推荐