大家好,我是 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,从业书籍笔记,人生职场认识等方面资料或文章。
2063