Nginx防盗链
什么是防盗链?
举个例子来说,有两个网站,A网站想使用B网站的图片,第一种方法是在A网站中直接添加B网站的图片链接,第二种是将B网站的图片下载回来,然后上传到A网站中使用,此时,如果B网站不想让A网站继续使用此图片了,可以通过添加一些限制来阻止A网站使用,这个阻止措施就是防盗链,添加了防盗链后,A网站再次使用通过URL请求B网站图片的时候,就会提示错误信息或者其他内容,从而保护了原图片,下面演示如何配置防盗链
环境准备:
| 域名 | IP | 用途 |
| www.server1.com | 192.168.130.128 | 要配置防盗链的服务器 |
| www.server2.com | 192.168.130.130 | 盗用服务器 |
1、首先配置server1服务器,让Nginx请求一个图片,配置如下:

在nginx根目录下创建文件夹image,在下面放一个1.png文件,访问www.server1.com/image/1.png,如下:

2、配置server2服务器,修改Nginx默认页面index.html,添加server1的图片URL,如图:

访问页面,可以看到server1的图片已经加载出来,如图:

防盗链配置
Nginx中实现防盗链的配置主要有两个模块:
- –with-http_secure_link_module:第三方模块
- refer模块:Nginx自带的
一、refer模块
refer模块原理是: 如果网站盗用了你的图片,那么用户在点击或者查看这个盗链内容时,发送 http 请求的头部中的 referer 字段将为该盗版网站的 url。此时我们通过获取这个头部信息,获取http 发起请求的页面,然后判断这个地址是否是我们的合法页面,不是则判断为盗链
referer中比较重要的指令就是valid_referers,它后面可以携带多个参数,表示多个referer头都是有效的,语法如下:
valid_referers none | blocked | server_names | string ...;
主要参数有:
- none:如果header中的referer为空,也能访问
- blocked:header中的referer不为空,但值被防火墙或代理服务器伪装过,比如不带http/https协议头的资源允许访问
- server_names:若 referer 中的站点域名和 server_names 中的某个域名匹配,则允许访问
- 最后是任意字符或者正则表达式
Nginx 会通过查看 referer 字段和 valid_referers 后面的 referer 列表进行匹配,如果匹配到了就将内置的变量$invalid_referer值设置为0,否则设置该值为1,匹配的过程不区分大小写
1、下面在server1服务器的Nginx配置防盗链设置,如图:

- ~*:开始正则匹配,不区分大小写
- .表示除换行符之外的所有字符,*表示匹配0次或多次
- (jpg|png|jpeg)$ 表示以这几个后缀结尾
2、再次通过server2域名来请求页面,可以看到图片已经无法加载,如图:

注意:可灵活使用none、blocker等参数
二、secure_link模块
通过 referer 头部值的防盗链方法过于脆弱,盗用者很容易通过伪造 referer 的值轻而易举跳过防盗措施,在 Nginx 中有一种更为高级的防盗方式,即基于 secure_link 模块,该模块能够检查请求链接的权限以及是否过期,多用于下载服务器防盗链。这个模块默认未编译进 Nginx,需要在源码编译时候添加–with-http_secure_link_module
该模块的通过验证 URL 中的哈希值的方式防盗链。它的防盗过程如下:
- 由服务器或者 Nginx 生成安全的加密后的 URL, 返回给客户端
- 客户端用安全的 URL 访问 Nginx,获取图片等资源,由 Nginx 的 secure_link 变量判断是否验证通过
通过配置 secure_link, secure_link_md5 指令,可实现对链接进行权限以及过期检查判断的功能,secure_link 模块的值有如下三种情况:
- 空字符串: 验证不通过
- 0: URL 过期
- 1: 验证通过
通常使用这个模块进行 URL 校验,那么如何生成合法的URL以及在Nginx中如何配置来校验这个URL呢?
生成合法的 URL 和 指令 secure_link_md5 有关,例如:
secure_link_md5 "$secure_link_expires$uri secret_key";
如果Nginx中的secure_link_md5 是上述配置,那么生成合法的URL命令如下:
#2023-11-06 11:23:15+过期时间,比如+300s,然后转换为时间戳为1699240995
echo -n '1699240995/1.png secret_key' | \
openssl md5 -binary | openssl base64 | tr +/ -_ | tr -d =
通过上述命令得到一个md5的值:YfagRTs8J-soGzU0_Whd1g,这个值很重要,接下来构造URL和指令secure_link有关,如果 secure_link 指令的配置如下:
secure_link $arg_md5,$arg_expires;
那么请求的url中必须带上md5和expires参数才能正常访问,例如:
http://www.server2.com/1.png?md5=YfagRTs8J-soGzU0_Whd1g&expires=1699240995
环境准备:
| 域名 | ip | 用途 |
| www.server2.com | 192.168.130.130 | 配置防盗链的服务器 |
1、首先在server2服务器配置Nginx,访问图片路径,如图:

在/usr/local/nginx/image下上传1.png,然后通过http://www.server2.com/1.png请求,如图:

2、继续修改server2服务器的Nginx配置,添加防盗链配置,如图:

从上图看出,我们自定义的是校验不通过的时候返回状态码405,现在我们再次请求下图片,如图:

返回405,说明防盗链规则已经生效,上面已经提过,如果要实现正常请求,需要在请求参数中携带md5和expires参数才可以,定义md5和expires的方法如下:
(1)、定义过期时间,这里使用shell演示,如下:
date -d "+300 seconds" +%s

(2)、使用过期时间生成md5,如下:
echo -n '1699256991/1.png secret_key' | openssl md5 -binary | openssl base64 | tr +/ -_ | tr -d =

注:secret_key需要与Nginx中配置的secret_key保持一致,否则请求不到资源
(3)、接下来使用url+md5+expires请求,即可正常访问了,如下:
http://www.server2.com/1.png?md5=ofVmCiO53rLdoisMOfZuPA&expires=1699256991
注意:在实际使用中,过期时间和 md5是需要通过开发代码来生成,因此,无论哪里需要请求这个资源,都需要md5和expires参数才能正常请求


