SpringBoot 实现图片防盗链功能

发布于:2025-02-10 ⋅ 阅读:(38) ⋅ 点赞:(0)

1. 实现目的

出于安全和性能的考虑,我们希望服务器返回的图片资源仅在指定网站内展示,防止爬虫或其它站点直接引用图片地址进行下载或展示,进而消耗服务器资源。简单来说,即在请求图片时通过检查 HTTP 请求头中的 Referer 来判断请求来源是否合法。


2. 简易实现方案

2.1 拦截器基本实现

在第一种方案中,代码写死了允许访问的域名(例如 “baidudu.com”),主要步骤如下:

  • 判断 URL 后缀
    当请求 URL 以 “.jpg”、“.png”、“.jpeg” 等图片格式结尾时,再进行后续判断。

  • 检查 Referer
    从请求头中取出 Referer,若不为空且包含预设允许的域名,则放行;否则返回 403 错误码,从而拒绝访问。

例如:

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    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("baidudu.com")) {
            return true;
        } else {
            response.sendError(HttpServletResponse.SC_FORBIDDEN);
            return false;
        }
    }
    return true;
}

注册拦截器时,采用 Spring Boot 的 WebMvcConfigurer 接口将该拦截器应用于所有请求路径。


3. 灵活配置实现方案

为了使防盗链的配置更加灵活,可以将配置项(例如是否开启防盗链、是否允许浏览器直接访问、白名单域名等)写在 application.yml 中,并利用配置类映射到 Java 对象中。

3.1 配置文件示例

application.yml 中定义如下配置:

img-protect:
  enabled: true
  allowBrowser: false
  allowReferer: baidudu.com

3.2 映射配置类

利用 @ConfigurationProperties 将配置项映射到 Java 类中,方便后续使用:

@Component
@ConfigurationProperties("img-protect")
public class ImgProtectConfig {
    private boolean enabled;
    private boolean allowBrowser;
    private String allowReferer;
    // getter/setter 略
}

3.3 拦截器实现细节

在新版拦截器中,通过注入上述配置类,实现如下逻辑:

  • 若防盗链功能未开启,则直接放行。
  • 对图片资源请求(通过 URL 后缀判断):
    • 如果 Referer 为空且允许浏览器直接访问(allowBrowser 为 true),则放行;
    • 如果 Referer 不为空,则调用辅助方法判断 Referer 是否包含配置中允许的域名(允许多个域名,逗号分隔);
    • 否则返回 403。

例如:

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    if (!imgProtectConfig.getEnabled()){
        return true;
    }
    String requestUrl = request.getRequestURL().toString();
    if (requestUrl.endsWith(".jpg") || requestUrl.endsWith(".png") || requestUrl.endsWith(".jpeg")) {
        String referer = request.getHeader("Referer");
        if (referer == null && imgProtectConfig.getAllowBrowser()){
            return true;
        } else if (referer != null && isAllowedDomain(referer)) {
            return true;
        } else {
            response.sendError(HttpServletResponse.SC_FORBIDDEN);
            return false;
        }
    }
    return true;
}

其中 isAllowedDomain 方法遍历配置中允许的多个域名进行比对。


4. 注意事项及局限性

虽然这种通过检查 Referer 实现的防盗链功能在一般场景下能有效防止资源被盗用,但仍存在一些不足之处:

  • Referer 伪造:恶意客户端可以伪造 Referer 头信息,绕过检测。
  • 漏报问题:攻击者可能利用 data URI 或 Base64 编码等方式绕过检查。
  • 误报问题:部分合法用户(例如使用隐私浏览器或代理服务器时)可能因 Referer 不匹配而被误拦截。
  • 反向代理问题:攻击者可能利用反向代理手法,通过 URL 路径中加入白名单域名绕过 contains 判断。

因此,该方法只是基本防护手段,并不能保证绝对安全,实际应用中可结合更严格的安全措施(如 Token 验证、Nginx 防盗链等)来共同提升防护效果。


5. 总结

本文展示了两种基于 Spring Boot 实现图片防盗链的方式:

  1. 简单写死配置的方式,直接在拦截器中判断 Referer;
  2. 基于配置文件灵活配置的方式,通过 application.yml 配置防盗链参数,并在拦截器中使用。

虽然这种方法能对一般情况下的盗链行为起到一定防护作用,但考虑到 Referer 可伪造等问题,实际项目中还需根据具体场景综合考虑更全面的安全策略。


网站公告

今日签到

点亮在社区的每一天
去签到