实战-Nginx实现图片防盗链-2023.12.15(测试成功)(超详细)


更新于:2023年12月15日

实战-Nginx实现图片防盗链-2023.12.15(测试成功)(超详细)

目录

原文地址

https://onedayxyy.cn/docs/nginx-FangDaoLian

前言

什么是图片盗链

首先我们聊聊什么是图片盗链?

盗链指的是其他网站不经过你的许可直接通过链接使用你网站上的资源,从而消耗你的带宽和资源,这不仅会影响你网站的性能,还有可能会导致资源被滥用。

简单来说,直接从你的网站上右键复制链接,粘贴到他自己的网站使用,实际请求的是你的服务器。

今天我们就来说说nginx如何实现配置静态资源服务器及防盗链实现。

一般常用的方法是在server或者location段中加入!

valid_referers   none  blocked  www.hihi123.com  hihi123.com;

详见下面的例子

valid_referers none | blocked | server_names | strings ….;
--none:允许没有http_refer的请求访问资源,检测 Referer 头域不存在的情况,则可以访问。 (none 表示空的来路,也就是直接访问,比如直接在浏览器打开一个图片)
--blocked:检测 Referer 头域的值被防火墙或者代理服务器删除或伪装的情况。 (blocked 表示被防火墙标记过的来路)
--server_names :只允许指定ip/域名来的请求访问资源(白名单)。可设置一个或多个 URL ,检测 Referer 头域的值是否是这些 URL 中的某一个。在生产环境中尽量使用域名,不使用ip。

1、准备一张防盗链提示图片

  • 首先准备一张防盗链提示图片(来源于百度)

盗链提示图片

  • 在**==nginx安装目录的html下==**创建res目录,将上述图片上传至此,可以直接访问到,将此图片作为盗链提示

注意:这个是之前博主的配置内容,下面我的这里配置的不一样哦,因为我按博主这里测试后有问题,一直访问不到这个图片(不知道是为啥🤣,自己还是对Nginx不熟悉哦!)……

[root@docusaurus-wiki res]# pwd
/usr/share/nginx/html/res
[root@docusaurus-wiki res]# ls
1.png

另外,那么问题来了:nginx的安装目录在哪里找?

自己探索:

cat /etc/nginx/nginx.conf

/usr/share/nginx

[root@docusaurus-wiki ~]# ls /usr/share/nginx/
html  modules
[root@docusaurus-wiki ~]# ls /usr/share/nginx/html/
404.html  50x.html  en-US  icons  img  index.html  nginx-logo.png  poweredby.png

##创建目录及上传防盗链图片
[root@docusaurus-wiki ~]# mkdir  /usr/share/nginx/html/res
[root@docusaurus-wiki ~]# cd  /usr/share/nginx/html/res
[root@docusaurus-wiki ~]# ls
1.png
  • 这里还需要配置下nginx,以便触发防盗链机制时,可以给请求对象反馈刚才上传的那张防盗链图片

既然博主这个测试方法有问题,那我就按如下方式来配置:

这里使用之前的nginx配置方法:

[root@docusaurus-wiki ~]# vim /etc/nginx/nginx.conf  ##注意:这段内容我只放到了https部分下面
%……  
  location /error {
       autoindex on; # 启用目录索引
       alias /FdangDaoLianImages;
       index index.html;   # 默认显示index.html文件,如果没有则列出目录内容
   }
……   
[root@docusaurus-wiki res]# mkdir /FdangDaoLianImages
[root@docusaurus-wiki res]# cd /FdangDaoLianImages/
[root@docusaurus-wiki FdangDaoLianImages]# rz
rz waiting to receive.**[root@docusaurus-wiki FdangDaoLianImages]# ll
total 152
-rw-rw-rw- 1 root root 154676 Dec 15 06:26 1.png
[root@docusaurus-wiki FdangDaoLianImages]# 

重启服务:

[root@docusaurus-wiki FdangDaoLianImages]# systemctl restart nginx
  • 验证(完美,已解决)

https://onedayxyy.cn/error/1.png

2、配置静态资源服务器

我的图片资源存放于服务器的/images目录下

vim /etc/nginx/nginx.conf
……
server {
     # 监听端口及其他配置项......

     # 静态资源服务配置
     location /images/  {
          alias /images/;

          valid_referers none blocked *.onedayxyy.cn onedayxyy.cn;
          if ( $invalid_referer ) {
               # 如不满足,指定访问如下资源
               rewrite ^/ https://onedayxyy.cn/error/1.png;
               return 403;
          }
     }
     # 其他配置项......
}
……

语法说明

valid_referers none | blocked | server_names | strings ….;
--none:允许没有http_refer的请求访问资源,检测 Referer 头域不存在的情况,则可以访问。
--blocked:检测 Referer 头域的值被防火墙或者代理服务器删除或伪装的情况。
--server_names :只允许指定ip/域名来的请求访问资源(白名单)。可设置一个或多个 URL ,检测 Referer 头域的值是否是这些 URL 中的某一个。在生产环境中尽量使用域名,不使用ip。

配置位置:(这里https和http都配置了,其实只要配置一个https就行的。)

  • 重启服务
systemctl restart nginx

3、验证

使用postman进行测试:

博主测试现象

添加Referer为www.cxs.plus测试,可以访问

使用其他域名测试,返回盗链提示图片

测试图片url

https://onedayxyy.cn/images/image-20231214065433.png

正常访问情况

正常情况下是在浏览器和typora里都可以访问图片的:

浏览器访问图片url:

typora里引用图片url:

配置nginx防盗链后再次测试

添加Referer为onedayxyy.cn测试,我的怎么也不能访问了呢?

奇怪……没搞懂!!!😭

  • 奇怪呀。。。

  • 博主文章里都是可以的娃。。。

使用其他域名测试,返回盗链提示图片

符合预期。

pc浏览器访问正常、自己typora里都显示正常、自己网站里图片也是显示正常的、自己手机端访问-是正常的

omg:把none取消后,完了。自己本地typora-手机坚果云-浏览器访问图片时就会跳转到防盗链提示图片了,但网站网页是正常显示的。(哈哈,千万不能禁止掉none。)

语法说明

valid_referers none | blocked | server_names | strings ….;
--none:允许没有http_refer的请求访问资源,检测 Referer 头域不存在的情况,则可以访问。
--blocked:检测 Referer 头域的值被防火墙或者代理服务器删除或伪装的情况。
--server_names :只允许指定ip/域名来的请求访问资源(白名单)。可设置一个或多个 URL ,检测 Referer 头域的值是否是这些 URL 中的某一个。在生产环境中尽量使用域名,不使用ip。
  • 配置过程

  • 现象截图

本地typora显示异常:

Snipaste_2023-12-15_07-29-34

我的网站图片显示正常:

Snipaste_2023-12-15_07-29-10

postman测试,依旧是访问不了的:

Snipaste_2023-12-15_07-30-42

手机坚果云显示异常:

image-20231215073919766

  • 把none添加回来后,一切都恢复正常了。

模拟其它网站来测试效果

符合预期。

  • 当前我nginx配置的防盗链配置如下

valid_referers none *.onedayxyyxx.cn onedayxyyxx.cn;

这里代表,只有*.onedayxyyxx.cn网站可以引用图床,其他网站引用的话就会触发防盗链;

或者不带有referer的请求也是可以引用防盗链的;

  • 开始测试效果

可以发现,此时自己的网站里的所有图片都显示异常了,符合预期。

  • 但是我的pc端typora应用,浏览器里访问图片url都是可以正常浏览图片的,手机端坚果云里访问md里的图片都是正常的:

pc端typora应用里图片显示正常:

浏览器里访问图片url正常:

手机端坚果云里访问md里的图片都是正常的:

4、结论

  • v1版本

自己的ecs nginx图床不需要做防盗链。

  1. 自己图床是利用nginx搭建的,又不是oss等,完全不耗费费用,加不加无所谓;
  2. 如果加了防盗链后,那么自己的typora也无法引用图片了,那我岂不是闲的没事儿干哈哈;(具体如何解决这个问题等后续再看吧)
  3. 自己的网站本来就是开源的,也方便大家去拷贝、阅读、传播,因此自己坚决不配置防盗链哦;
  • v2版本

这里为自己的nginx图床设置了防盗链功能:(宽松模式)

我自己typora、别人typora都可以正常使用图片;

浏览器里都可以直接访问图片url;

我自己网站可以正常使用图片,但是别人网站不能直接使用我的图片,否则会触发防盗链机制;

5、nginx完整代码

nginx配置文件

/etc/nginx/nginx.conf

[root@docusaurus-wiki ~]# cat /etc/nginx/nginx.conf
# For more information on configuration, see:
#   * Official English Documentation: http://nginx.org/en/docs/
#   * Official Russian Documentation: http://nginx.org/ru/docs/

user root;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;

events {
    worker_connections 1024;
}

http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 4096;

    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;

    # Load modular configuration files from the /etc/nginx/conf.d directory.
    # See http://nginx.org/en/docs/ngx_core_module.html#include
    # for more information.
    include /etc/nginx/conf.d/*.conf;

#    server {
#        listen       80;
#        listen       [::]:80;
#        server_name  onedayxyy.cn;
#        #root         /usr/share/nginx/html;
#        root         /root/rsync/public;
#
#        # Load configuration files for the default server block.
#        include /etc/nginx/default.d/*.conf;
#
#        error_page 404 /404.html;
#        location = /404.html {
#        }
#
#        error_page 500 502 503 504 /50x.html;
#        location = /50x.html {
#        }
#
#        #将所有HTTP请求通过rewrite指令重定向到HTTPS。
#       rewrite ^(.*)$ https://$host$1;
#       location / {
#               index index.html index.htm;
#       }
#
#    }

# Settings for a TLS enabled server.
#
    server {
        listen       443 ssl http2;
        listen       [::]:443 ssl http2;
        server_name  www.onedayxyy.cn;
        root         /root/rsync-wiki/build;

    location /hexoblog {
        alias /root/rsync/public;
        index index.html;
    }


    location /images {
        alias /images;
        index index.html;

        valid_referers none blocked  *.onedayxyy.cn onedayxyy.cn;
        if ( $invalid_referer ) {
               # 如不满足,指定访问如下资源
             rewrite ^/ https://onedayxyy.cn/error/1.png;
             return 403;
        }
    }


    location /error {
        autoindex on; # 启用目录索引
        alias /FdangDaoLianImages;
        index index.html;   # 默认显示index.html文件,如果没有则列出目录内容
    }

        ssl_certificate "cert/www.onedayxyy.cn.pem";
        ssl_certificate_key "cert/www.onedayxyy.cn.key";

        ssl_session_cache shared:SSL:1m;
        ssl_session_timeout  10m;
        #ssl_ciphers HIGH:!aNULL:!MD5;
        #自定义设置使用的TLS协议的类型以及加密套件(以下为配置示例,请您自行评估是否需要配置)
        #TLS协议版本越高,HTTPS通信的安全性越高,但是相较于低版本TLS协议,高版本TLS协议对浏览器的兼容性较差。
        ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
        ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;

        ssl_prefer_server_ciphers on;



        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;

        error_page 404 /404.html;
            location = /40x.html {
        }

        error_page 500 502 503 504 /50x.html;
            location = /50x.html {
        }


    }

  server {
    listen 80;
    #填写证书绑定的域名
    server_name www.onedayxyy.cn;
    root         /root/rsync-wiki/build;
    #将所有HTTP请求通过rewrite指令重定向到HTTPS。
    rewrite ^(.*)$ https://$host$1;

    location / {
        index index.html index.htm;
    }

    location /hexoblog {
        alias /root/rsync/public;
        index index.html;
    }


    location /images {
        alias /images;
        index index.html;

        valid_referers none blocked *.onedayxyy.cn onedayxyy.cn;
        if ( $invalid_referer ) {
               # 如不满足,指定访问如下资源
             rewrite ^/ https://onedayxyy.cn/error/1.png;
             return 403;
        }
    }


  }


}
[root@docusaurus-wiki ~]# 

FAQ

猜想

  • 预测

image-20231215074030203

如果其他网站直接把我的图片url在浏览器打开都是可以正常使用的,但是如果把它放到自己网站直接渲染使用时,那么就会触发防盗链机制了。

要么他把这些本地图片全部下载下来,然后传到自己图床;

要么触发我的防盗链机制;

  • 防盗链理想状态

我自己的网站、typora可以正常使用;

其他人只要拷贝图片到typora等本地,在自己网站使用时,就会触发我的防盗链机制,这样才是最合理的;

目前实现的状态:

别人人不能在自己网站使用我的图片,但是如果复制到本地typora,还是可以正常显示图片的,也是可以直接下载图片的;

  • 另外,别人网站如果使用我的图片的话,那么这个图片refer应该是他的网站域名吧。。。???–>是的

  • 另外,如果别人本地typora使用我的图片,那么回消耗我服务器的流量吗???–会的吧。


  • 问题(这个问题已经已解决了,上面那个demo已经验证过了,只要我们添加none参数后,自己和别人的本地typora应用都是可以使用图片的。

我如果在自己ecs的nginx上配置了防盗链的话,是不是我pc本地的typora里的md文档就不能正常显示图片了呢?

gpt提问

我如果在自己ecs的nginx上配置了防盗链的话,是不是我pc本地的typora里的md文档就不能正常显示图片了呢?

配置防盗链(Referer 防盗链)通常会限制图片等资源只能被特定的域名请求,从而防止未经授权的站点或应用程序使用这些资源。如果你在 ECS 上的 Nginx 配置了防盗链,而你的本地 Typora 中的 Markdown 文档引用了这些图片,可能会导致在 Typora 中无法正常显示图片的问题。

当你在 Typora 编辑器中预览或导出 Markdown 文档时,Typora 会尝试加载文档中引用的图片。如果这些图片受到防盗链限制,请求将被拒绝,从而导致无法显示图片。

为了解决这个问题,你可以考虑以下几种方法:

  1. 放宽防盗链设置: 考虑在 Nginx 的防盗链配置中放宽限制,允许本地 Typora 访问图片资源。这可能涉及到调整 Nginx 的配置文件。(🤣)
  2. 使用相对路径: 在 Typora 中使用相对路径引用图片,而不是绝对路径。相对路径可能不受防盗链的影响,但要确保相对路径在本地和服务器上都能正确找到图片。(废话🤣)
  3. 使用专门的存储服务: 考虑将图片等资源存储在专门的存储服务上,如对象存储服务(如阿里云 OSS、腾讯云 COS、AWS S3 等),并设置适当的访问权限,以便 Typora 和 ECS 上的 Nginx 都能够正常访问。

在采取以上措施之前,请确保了解防盗链的目的和影响,以及所做更改可能带来的安全性和访问控制方面的影响。

记录

1、针对不同的文件类型

仅记录,未实际测试。

location ~ .*\.(wma|wmv|asf|mp3|mmf|zip|rar|jpg|gif|png|swf|flv)$ {
     valid_referers none blocked *.765h.com 765h.com;
     if ($invalid_referer) {
     #rewrite ^/ http://www.765h.com/error.html;
     return 403;
      }
}

第一行:wma|gif|jpg|png|swf|flv

表示对wma、gif、jpg、png、swf、flv后缀的文件实行防盗链

第二行:*.765h.com 765h.com
表示对*.765h.com 765h.com这2个来路进行判断(*代表任何,任何的二级域名),你可以添加更多;

if{}里面内容的意思是,如果来路不是指定来路就跳转到403错误页面,当然直接返回404也是可以的,也可以是图片。

2、针对不同的目录

location /img/ {
    root /data/img/;
    valid_referers none blocked *.765h.com 765h.com;
    if ($invalid_referer) {
                   rewrite  ^/  http://www.765h.com/p_w_picpaths/error.gif;
                   #return   403;
    }
}

以上是nginx自带的防盗链功能。(本次使用的就是这个功能)

3、nginx 的第三方模块ngx_http_accesskey_module 来实现下载文件的防盗链

仅记录,未实际测试。

安装Nginx和nginx-http-access模块

#tar zxvf nginx-0.7.61.tar.gz
#cd nginx-0.7.61/
#tar xvfz nginx-accesskey-2.0.3.tar.gz
#cd nginx-accesskey-2.0.3 
#vi config
#把HTTP_MODULES="$HTTP_MODULES $HTTP_ACCESSKEY_MODULE" 修改成HTTP_MODULES="$HTTP_MODULES ngx_http_accesskey_module" (这是此模块的一个bug)
#./configure --user=www --group=www --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module --add-module=/root/nginx-accesskey-2.0.3

编译成功后,在主配置文件加入类似下面的代码:

server{ 
..... 
    location /download { 
        accesskey             on;
        accesskey_hashmethod  md5;
        accesskey_arg         "key";
        accesskey_signature   "mypass$remote_addr";
    } 
}

/download 为你下载的目录。

前台php产生的下载路径格式是:

1.http://*****.com/download/1.zip?key=<?php echo md5('mypass'.$_SERVER["REMOTE_ADDR"]);?>
这样,当访问没有跟参数一样时,其他用户打开时,就出现:403

NginxHttpAccessKeyModule第三方模块,实现方法如下:

  1. 下载Nginx HttpAccessKeyModule模块文件: Nginx-accesskey-2.0.3.tar.gz;

  2. 解压此文件后,找到nginx-accesskey-2.0.3下的config文件。编辑此文件:替换其中的"$HTTP_ACCESSKEY_MODULE"为"ngx_http_accesskey_module"

  3. 用一下参数重新编译nginx:

./configure --add-module=path/to/nginx-accesskey
  1. 修改nginx的conf文件,添加以下几行:
location /download {
  accesskey             on;
  accesskey_hashmethod  md5;
  accesskey_arg         "key";
  accesskey_signature   "mypass$remote_addr";
}

其中:
accesskey为模块开关;
accesskey_hashmethod为加密方式MD5或者SHA-1;
accesskey_arg为url中的关键字参数;
accesskey_signature为加密值,此处为mypass和访问IP构成的字符串。

访问测试脚本download.php:

<?
$ipkey= md5("mypass".$_SERVER['REMOTE_ADDR']);
$output_add_key="<a href=http://www.example.cn/download/G3200507120520LM.rar?key=".$ipkey.">download_add_key</a><br />";
$output_org_url="<a href=http://www.example.cn/download/G3200507120520LM.rar>download_org_path</a><br />";
echo $output_add_key;
echo $output_org_url;
?>

访问第一个download_add_key链接可以正常下载,第二个链接download_org_path会返回403 Forbidden错误。

如果不怕麻烦,有条件实现的话,推荐使用Nginx HttpAccessKeyModule这个东西。

他的运行方式是:如我的download 目录下有一个 file.zip 的文件。对应的URI 是http://www.765h.com/download/file.zip
使用ngx_http_accesskey_module 模块后http://www.765h.com/download/file.zip?key=09093abeac094. 只有给定的key值正确了,才能够下载download目录下的file.zip。而且 key 值是根据用户的IP有关的,这样就可以避免被盗链了。

据说Nginx HttpAccessKeyModule现在连迅雷都可以防了,可以尝试一下。

参考

https://blog.51cto.com/u_64214/8577766

https://blog.51cto.com/u_64214/5085592

https://blog.51cto.com/haierxing/835965

关于我

我的博客主旨:

  • 排版美观,语言精炼;
  • 文档即手册,步骤明细,拒绝埋坑,提供源码;
  • 本人实战文档都是亲测成功的,各位小伙伴在实际操作过程中如有什么疑问,可随时联系本人帮您解决问题,让我们一起进步!

🍀 微信二维码
x2675263825 (舍得), qq:2675263825。

image-20230107215114763

🍀 微信公众号
《云原生架构师实战》

image-20230107215126971

🍀 个人博客站点

http://onedayxyy.cn/

🍀 语雀

https://www.yuque.com/xyy-onlyone

🍀 csdn

https://blog.csdn.net/weixin_39246554?spm=1010.2135.3001.5421

image-20230107215149885

🍀 知乎

https://www.zhihu.com/people/foryouone

image-20230107215203185

最后

好了,关于本次就到这里了,感谢大家阅读,最后祝大家生活快乐,每天都过的有意义哦,我们下期见!


  目录