SpringBoot实现图片防盗链功能

 更新时间:2024年04月29日 08:26:43   作者:前阿里高级码农  
出于安全考虑,我们需要后端返回的图片只允许在某个网站内展示,不想被爬虫拿到图片地址后被下载,或者,不想浏览器直接访问图片链接,所以本文将给大家介绍SpringBoot实现图片防盗链功能,需要的朋友可以参考下

前言

出于安全考虑,我们需要后端返回的图片只允许在某个网站内展示,不想被爬虫拿到图片地址后被下载。或者,不想浏览器直接访问图片链接。

出于性能考虑,不想要别人的网站,拿着我们的图片链接去展示,白白消耗自己的服务器资源。

故而可在springboot中,使用简单的图片防盗链规则。拦截掉一些处理。

1、代码实现

本篇实战代码是简易版,代码写死配置

1-1、创建拦截器类

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse;
    public class ImageProtectionInterceptor implements HandlerInterceptor {    
       
        private static final 
       
        String ALLOWED_DOMAIN = "baidudu.com"; // 允许的域名    @Override    
        
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) 
        
        throws Exception {        // 获取请求的 URL        
      
        String requestUrl = request.getRequestURL().toString();        // 判断请求是否以图片后缀结尾        
      
        if (requestUrl.endsWith(".jpg") || requestUrl.endsWith(".png") || requestUrl.endsWith(".jpeg")) {            // 获取请求的来源域名            
      
        String referer = request.getHeader("Referer");            // 检查来源域名是否符合预期            
      
        if (referer != null && referer.contains(ALLOWED_DOMAIN)) {                
         
            return true; // 符合防盗链要求,放行请求            
           
            } else {                
         
            response.sendError(HttpServletResponse.SC_FORBIDDEN); // 返回 403 Forbidden                
         
            return false; // 拦截请求         
         
            }       
         
   }        
         
            return true; // 对非图片资源请求放行  
            }
        
    }

2、代码实现(灵活配置)

2-1、在 application.yml 中配置信息

# 图片防盗链配置img-protect: 
# 图片防盗链保护开关  
enabled: true  
# 是否允许浏览器直接访问  
allowBrowser: false  
# 图片防盗链白名单,多个用逗号分隔【不填则所有网站都拦截】 
allowReferer: baidudu.com

2-2、创建配置文件映射类

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component@ConfigurationProperties("img-protect")

        public class ImgProtectConfig {    
          private boolean enabled;    
   
          private boolean allowBrowser;    
  
          private String allowReferer;    
  
          public boolean getEnabled() {        
           
               return enabled;    
        
    }    
    
          public void setEnabled(boolean enabled) {        
              
              this.enabled = enabled;   
              
              
          }    
              public boolean getAllowBrowser() {        
                  
                  return allowBrowser;   
                  
                  
              }   
              
         public void setAllowBrowser(boolean allowBrowser) {       
                 
            this.allowBrowser = allowBrowser;    
             
             
         }    
         
         public String getAllowReferer() {       
             
             return allowReferer;    
             
         }    
         
         public void setAllowReferer(String allowReferer) {        
             
             this.allowReferer = allowReferer;   
             
             
         }
            
        }

2-3、创建拦截器类

import 上方2-2创建的类路径.ImgProtectConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

@Componentpublic 

class ImageProtectionInterceptor implements HandlerInterceptor {    
   
    @Autowired    
    
    private ImgProtectConfig imgProtectConfig;    
    
    @Override    
    
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {  // 判断是否开启图片防盗链功能        
   
    if (!imgProtectConfig.getEnabled()){            
        
        return true;       
        
    }                // 获取请求的 URL        
    
    String requestUrl = request.getRequestURL().toString();        // 判断请求是否以图片后缀结尾        
    
    if (requestUrl.endsWith(".jpg") || requestUrl.endsWith(".png") || requestUrl.endsWith(".jpeg")) {            // 获取请求的来源域名            
    
    String referer = request.getHeader("Referer");            // 检查来源域名是否符合预期,referer 为 null 则说明是浏览器直接访问。            
    
    if (referer == null && imgProtectConfig.getAllowBrowser()){                
        
        return true; // 符合防盗链要求,放行请求            
        
        
    }else if (referer != null && isAllowedDomain(referer)) {                
        
    return true; // 符合防盗链要求,放行请求            
    
        
    } else {                
        
    response.sendError(HttpServletResponse.SC_FORBIDDEN); // 返回 403 Forbidden                
    
    return false; // 拦截请求           
        
         }       
    
    }        
    
    return true; // 对非图片资源请求放行    
    
        
    }    // 检查是否来自允许的域名    
    
    private boolean isAllowedDomain(String referer) {        
        
        // 获取允许的域名        
        String allowedReferers = imgProtectConfig.getAllowReferer();        
        
        // 如果允许的域名不为空        
        if (allowedReferers.trim() != null && !"".equals(allowedReferers.trim())) {            
            
            // 将允许的域名分割成字符串数组            
        Set<String> allowedDomains = new HashSet<>(Arrays.asList(allowedReferers.split(",")));            
        
        // 遍历允许的域名            
        for (String allowedDomain : allowedDomains) {                
        
        // 如果请求的域名包含允许的域名,则返回true                
        if (referer.contains(allowedDomain.trim())) {                    
            
            return true;               
            
            
        }           
        
            
        }      
        
            
        }        
        
        // 否则返回
        false        
        
        return false;    
        
    }
    
}

2-4、注册拦截器

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration

    public class WebConfig implements WebMvcConfigurer {  
        
        // 不能再使用 new 方式创建对象 !!!  
        @Autowired    
         private ImageProtectionInterceptor imageProtectionInterceptor;   
        
        @Override    
        public void addInterceptors(InterceptorRegistry registry) {        
        
        // 注册拦截器,拦截所有请求        
        registry.addInterceptor(imageProtectionInterceptor)                
        .addPathPatterns("/**"); 
        // 拦截所有请求    
        }
        
    }

结束语

以上防盗链拦截器基本实现可以对付一般情况下的图片盗链,但并不能保证绝对安全。

可能出现以下等情况:

  • Referer 伪造: 恶意客户端可以伪造 referer 头。攻击者可以伪造有效的 referer 来绕过保护。

  • 漏报: 攻击者可能找到绕过 referer 检查的方法(例如使用 data URI 或 base64 编码的图片)。

  • 误报: 合法用户可能因为 referer 不匹配而被阻止(例如隐私浏览器或代理服务器)。

  • 反向代理: 攻击者可以在url路径中,添加域名白名单作为反向代理路径,绕开代码的contains方法检查。

以上就是SpringBoot实现图片防盗链功能的详细内容,更多关于SpringBoot图片防盗链的资料请关注脚本之家其它相关文章!

相关文章

  • Scala中的mkString的具体使用方法

    Scala中的mkString的具体使用方法

    这篇文章主要介绍了Scala中的mkString的具体方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-06-06
  • Java Map 通过 key 或者 value 过滤的实例代码

    Java Map 通过 key 或者 value 过滤的实例代码

    这篇文章主要介绍了Java Map 通过 key 或者 value 过滤的实例代码,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下
    2018-06-06
  • Java中的线程ThreadLocal详细解析

    Java中的线程ThreadLocal详细解析

    这篇文章主要介绍了Java中的线程ThreadLocal详细解析,ThreadLocal是线程本地变量,存储在ThreadLocal里面的数据都是线程安全的,一般ThreadLocal适用的场景多是各个线程间没有变量共享需要的同步问题场景,需要的朋友可以参考下
    2023-10-10
  • java 中枚举类enum的values()方法的详解

    java 中枚举类enum的values()方法的详解

    这篇文章主要介绍了java 中枚举类enum的values()方法的详解的相关资料,希望通过本文大家能够掌握这部分内容,需要的朋友可以参考下
    2017-09-09
  • java验证用户是否已经登录 java实现自动登录

    java验证用户是否已经登录 java实现自动登录

    这篇文章主要介绍了java验证用户是否已经登录,java实现自动登录,感兴趣的小伙伴们可以参考一下
    2016-04-04
  • springmvc实现文件上传功能

    springmvc实现文件上传功能

    这篇文章主要为大家详细介绍了springmvc实现文件上传功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-03-03
  • java基于JSON实现前后端交互(附代码)

    java基于JSON实现前后端交互(附代码)

    本文主要介绍了java基于JSON实现前后端交互,通过实际代码示例展示了如何前后端JSON交互,具有一定的参考价值,感兴趣的可以了解一下
    2024-01-01
  • Java实现字符串倒序输出的四种方法汇总

    Java实现字符串倒序输出的四种方法汇总

    这篇文章主要介绍了Java实现字符串倒序输出的四种方法汇总,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-06-06
  • Spring MVC各种参数进行封装的方法实例

    Spring MVC各种参数进行封装的方法实例

    这篇文章主要给大家介绍了关于Spring MVC各种参数进行封装的相关资料,SpringMVC内置多种数据类型转换器,可以根据请求中的参数与后端控制器方法的参数的关系为我们实现简单的数据封装,需要的朋友可以参考下
    2023-06-06
  • Java流程控制语句最全汇总(下篇)

    Java流程控制语句最全汇总(下篇)

    这篇文章主要介绍了Java流程控制语句最全汇总(下篇),本文章内容详细,通过案例可以更好的理解数组的相关知识,本模块分为了三部分,本次为下篇,需要的朋友可以参考下
    2023-01-01

最新评论